diff --git a/.gitignore b/.gitignore index 9f4392f..708346d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ build/ *.tar *.pyd -*.egg-info \ No newline at end of file +*.egg-info +*.json \ No newline at end of file diff --git a/DCVC-family/DCVC-RT/README.md b/DCVC-family/DCVC-RT/README.md new file mode 100644 index 0000000..118e80a --- /dev/null +++ b/DCVC-family/DCVC-RT/README.md @@ -0,0 +1,157 @@ +# Introduction + +Official Pytorch implementation for DCVC-RT: [Towards Practical **R**eal-**T**ime Neural Video Compression](https://arxiv.org/abs/2502.20762), in CVPR 2025. Project page: https://dcvccodec.github.io/. + +- The first end-to-end neural video codec achieving 100+ FPS 1080p coding and 4K real-time coding with a comparable compression ratio with ECM. + +Beyond this, DCVC-RT pursues a more practical neural video codec solution and supports various practical features: +- **Wide bitrate range in single model**: A single model enables continuous and controllable bitrate adjustments. DCVC-RT can compress at a wide bitrate range for different coding scenarios. +- **Rate control**: By adjusting quantization parameters, DCVC-RT effectively supports dynamic and various network conditions during real communication scenario. +- **Unified YUV and RGB coding**: While DCVC-RT is primarily optimized for the widely adopted YUV format, it can seamlessly adapt to RGB content coding. + +We are continuously exploring additional practical functionalities and will provide further NVC solutions in this repository. + + + +## Abstract + +We introduce a practical real-time neural video codec (NVC) designed to deliver high compression ratio, low latency and broad versatility. In practice, the coding speed of NVCs depends on 1) computational costs, and 2) non-computational operational costs, such as memory I/O and the number of function calls. While most efficient NVCs prioritize reducing computational cost, we identify operational cost as the primary bottleneck to achieving higher coding speed. Leveraging this insight, we introduce a set of efficiency-driven design improvements focused on minimizing operational costs. Specifically, we employ implicit temporal modeling to eliminate complex explicit motion modules, and use single low-resolution latent representations rather than progressive downsampling. These innovations significantly accelerate NVC without sacrificing compression quality. Additionally, we implement model integerization for consistent cross-device coding and a module-bank-based rate control scheme to improve practical adaptability. Experiments show our proposed DCVC-RT achieves an impressive average encoding/decoding speed at 125.2/112.8 fps (frames per second) for 1080p video, while saving an average of 21\% in bitrate compared to H.266/VTM. + +# Prerequisites +* Python 3.12 and conda, get [Conda](https://www.anaconda.com/) +* CUDA 12.6 (other versions may also work. Make sure the CUDA version matches with pytorch.) +* pytorch (We have tested that pytorch-2.6 works. Other versions may also work.) +* Environment + ``` + conda create -n $YOUR_PY_ENV_NAME python=3.12 + conda activate $YOUR_PY_ENV_NAME + + pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126 + pip install -r requirements.txt + ``` + +# Test dataset + +We support arbitrary original resolution. The input video resolution will be padded automatically. The reconstructed video will be cropped back to the original size. The distortion (PSNR) is calculated at original resolution. + +## YUV 420 content + +Put *.yuv in the folder structure similar to the following structure. + + /media/data/HEVC_B/ + - BQTerrace_1920x1080_60.yuv + - BasketballDrive_1920x1080_50.yuv + - ... + /media/data/HEVC_D/ + /media/data/HEVC_C/ + ... + +The dataset structure can be seen in dataset_config_example_yuv420.json. + +## RGB content + +We highly suggest testing YUV420 content. To test RGB content, please refer to the DCVC-FM folder. + +# Build the project + +Please build the C++ code to support bitstream writing and customized CUDA kernels to fuse operations. + +```bash +sudo apt-get install cmake g++ ninja-build +conda activate $YOUR_PY_ENV_NAME +cd ./src/cpp/ +pip install . +cd ../layers/extensions/inference/ +pip install . +``` + +If the CUDA kernels fail to load successfully in inference, the standard output will display: ```cannot import cuda implementation for inference, fallback to pytorch.``` + +## CPU performance scaling + +Note that the arithmetic coding runs on the CPU, please make sure your CPU runs at high performance while writing the actual bitstream. Otherwise, the arithmetic coding may take a long time. + +Check the CPU frequency by +``` +grep -E '^model name|^cpu MHz' /proc/cpuinfo +``` + +Run the following command to maximum CPU frequency +``` +echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +``` + +Run the following command to recover the default frequency +``` +echo ondemand | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +``` + +# Pretrained models + +* Download [our pretrained models](https://1drv.ms/f/c/2866592d5c55df8c/Esu0KJ-I2kxCjEP565ARx_YB88i0UnR6XnODqFcvZs4LcA?e=by8CO8) and put them into ./checkpoints folder. +* There are 2 models, one for image coding and the other for video coding. + +# Test the models + +Example to test pretrained model with four rate points: +```bash +python test_video.py --model_path_i ./checkpoints/cvpr2025_image.pth.tar --model_path_p ./checkpoints/cvpr2025_video.pth.tar --rate_num 4 --test_config ./dataset_config_example_yuv420.json --cuda 1 -w 1 --write_stream 1 --force_zero_thres 0.12 --output_path output.json --force_intra_period -1 --reset_interval 64 --force_frame_num -1 --check_existing 0 --verbose 0 +``` + +It is recommended that the ```-w``` number is equal to your GPU number. + +You can also specify different ```--rate_num``` values (2~64) to test finer bitrate adjustment. + +To measure coding speed, you can set ```--verbose``` value to `1` (sequence-level measuring) or `2` (frame-level measuring). This will automatically measure encoding and decoding speeds, print them in the terminal, and record the average speeds in ```avg_frame_encoding_time``` and ```avg_frame_decoding_time``` in the output JSON file. +- Note that ```test_time``` is the total testing time for the entire sequence, which includes I/O time, encoding time, decoding time, and distortion calculation time. The overhead from I/O and distortion calculation is much larger than the encoding/decoding time itself, so we exclude these overheads to measure the precise coding time. +- Additionally, please make sure ```time.time()``` provides sufficient precision on the tested platform. For instance, our experience is that the precision is adequate on our Ubuntu device, but insufficient on our Windows device. + +# Comparing with other method + +Bit saving over VTM-17.0 (UVG all frames with single intra-frame setting (i.e. intra-period = –1) and YUV420 colorspace.) + + + +The BD-Rate and 1080p encoding/decoding speed on NVIDIA A100 GPU + + + +The complexity analysis and encoding/decoding speed evaluation across various resolutions and devices. + + + +## Image compression performance + +Notably, the intra-frame codec in DCVC-RT also delivers impressive performance. On Kodak, DCVC-RT-Intra achieves an 11.1% bitrate reduction compared to VTM, with a over 10× faster decoding speed than previous state-of-the-art learned image codecs. For encoding, DCVC-RT-Intra also offers a similar speed advantage. For 1080p content, DCVC-RT-Intra achieves an impressive encoding/decoding speed of 40.7 FPS / 44.2 FPS on an NVIDIA A100 GPU. + + + +## On the comparison + +Please note that different methods may use different configurations to test different models, such as +* Source video may be different, e.g., cropped or padded to the desired resolution. +* Intra period may be different, e.g., 96, 32, 12, or 10. +* Number of encoded frames may be different. + +So, it does not make sense to compare the numbers in different methods directly, unless making sure they are using same test conditions. + +Please find more details on the [test conditions](../test_conditions.md). + +# Acknowledgement +The implementation of DCVC-RT is based on [CompressAI](https://github.com/InterDigitalInc/CompressAI). + +# Citation +If you find this work useful for your research, please cite: + +``` +@inproceedings{jia2025towards, + title={Towards Practical Real-Time Neural Video Compression}, + author={Jia, Zhaoyang and Li, Bin and Li, Jiahao and Xie, Wenxuan and Qi, Linfeng and Li, Houqiang and Lu, Yan}, + booktitle={{IEEE/CVF} Conference on Computer Vision and Pattern Recognition, + {CVPR} 2025, Nashville, TN, USA, June 11-25, 2024}, + year={2025} +} +``` + +# Trademarks +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft’s Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies. diff --git a/assets/RD-Curve.png b/DCVC-family/DCVC-RT/assets/RD-Curve.png similarity index 100% rename from assets/RD-Curve.png rename to DCVC-family/DCVC-RT/assets/RD-Curve.png diff --git a/DCVC-family/DCVC-RT/assets/bd_rate_speed.png b/DCVC-family/DCVC-RT/assets/bd_rate_speed.png new file mode 100644 index 0000000..3773a1d Binary files /dev/null and b/DCVC-family/DCVC-RT/assets/bd_rate_speed.png differ diff --git a/DCVC-family/DCVC-RT/assets/complexity.png b/DCVC-family/DCVC-RT/assets/complexity.png new file mode 100644 index 0000000..8bee325 Binary files /dev/null and b/DCVC-family/DCVC-RT/assets/complexity.png differ diff --git a/DCVC-family/DCVC-RT/assets/intra_compare.png b/DCVC-family/DCVC-RT/assets/intra_compare.png new file mode 100644 index 0000000..b3cf9b1 Binary files /dev/null and b/DCVC-family/DCVC-RT/assets/intra_compare.png differ diff --git a/DCVC-family/DCVC-RT/assets/practical_performance.png b/DCVC-family/DCVC-RT/assets/practical_performance.png new file mode 100644 index 0000000..31675dc Binary files /dev/null and b/DCVC-family/DCVC-RT/assets/practical_performance.png differ diff --git a/DCVC-family/DCVC-RT/checkpoints/.gitkeep b/DCVC-family/DCVC-RT/checkpoints/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dataset_config_example_yuv420.json b/DCVC-family/DCVC-RT/dataset_config_example_yuv420.json similarity index 100% rename from dataset_config_example_yuv420.json rename to DCVC-family/DCVC-RT/dataset_config_example_yuv420.json diff --git a/DCVC-family/DCVC-RT/requirements.txt b/DCVC-family/DCVC-RT/requirements.txt new file mode 100644 index 0000000..21ad776 --- /dev/null +++ b/DCVC-family/DCVC-RT/requirements.txt @@ -0,0 +1,7 @@ +numpy>=1.20.0 +scipy +matplotlib +tqdm +bd-metric +pillow +pybind11 diff --git a/DCVC-family/DCVC-RT/src/cpp/py_rans/py_rans.cpp b/DCVC-family/DCVC-RT/src/cpp/py_rans/py_rans.cpp new file mode 100644 index 0000000..1f5d047 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/cpp/py_rans/py_rans.cpp @@ -0,0 +1,393 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "py_rans.h" + +#include +#include +#include +#include +#include + +namespace py = pybind11; + +RansEncoder::RansEncoder() +{ + m_encoder0 = std::make_shared(); + m_encoder1 = std::make_shared(); +} + +void RansEncoder::encode_y(const py::array_t& symbols, const int cdf_group_index) +{ + py::buffer_info symbols_buf = symbols.request(); + int16_t* symbols_ptr = static_cast(symbols_buf.ptr); + + int symbolSize = static_cast(symbols.size()); + if (m_use_two_encoders) { + int symbolSize0 = symbolSize / 2; + int symbolSize1 = symbolSize - symbolSize0; + + auto vec_symbols0 = std::make_shared>(symbolSize0); + memcpy(vec_symbols0->data(), symbols_ptr, symbolSize0 * sizeof(int16_t)); + m_encoder0->encode_y(vec_symbols0, cdf_group_index); + auto vec_symbols1 = std::make_shared>(symbolSize1); + memcpy(vec_symbols1->data(), symbols_ptr + symbolSize0, symbolSize1 * sizeof(int16_t)); + m_encoder1->encode_y(vec_symbols1, cdf_group_index); + } else { + auto vec_symbols0 = std::make_shared>(symbolSize); + memcpy(vec_symbols0->data(), symbols_ptr, symbolSize * sizeof(int16_t)); + m_encoder0->encode_y(vec_symbols0, cdf_group_index); + } +} + +void RansEncoder::encode_z(const py::array_t& symbols, const int cdf_group_index, + const int start_offset, const int per_channel_size) +{ + py::buffer_info symbols_buf = symbols.request(); + int8_t* symbols_ptr = static_cast(symbols_buf.ptr); + + int symbolSize = static_cast(symbols.size()); + if (m_use_two_encoders) { + int symbolSize0 = symbolSize / 2; + int symbolSize1 = symbolSize - symbolSize0; + int channel_half = symbolSize0 / per_channel_size; + + auto vec_symbols0 = std::make_shared>(symbolSize0); + memcpy(vec_symbols0->data(), symbols_ptr, symbolSize0 * sizeof(int8_t)); + m_encoder0->encode_z(vec_symbols0, cdf_group_index, start_offset, per_channel_size); + auto vec_symbols1 = std::make_shared>(symbolSize1); + memcpy(vec_symbols1->data(), symbols_ptr + symbolSize0, symbolSize1 * sizeof(int8_t)); + m_encoder1->encode_z(vec_symbols1, cdf_group_index, start_offset + channel_half, + per_channel_size); + } else { + auto vec_symbols0 = std::make_shared>(symbolSize); + memcpy(vec_symbols0->data(), symbols_ptr, symbolSize * sizeof(int8_t)); + m_encoder0->encode_z(vec_symbols0, cdf_group_index, start_offset, per_channel_size); + } +} + +int RansEncoder::add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const py::array_t& offsets) +{ + py::buffer_info cdfs_sizes_buf = cdfs_sizes.request(); + py::buffer_info offsets_buf = offsets.request(); + int32_t* cdfs_sizes_ptr = static_cast(cdfs_sizes_buf.ptr); + int32_t* offsets_ptr = static_cast(offsets_buf.ptr); + + int cdf_num = static_cast(cdfs_sizes.size()); + auto vec_cdfs_sizes = std::make_shared>(cdf_num); + memcpy(vec_cdfs_sizes->data(), cdfs_sizes_ptr, sizeof(int32_t) * cdf_num); + auto vec_offsets = std::make_shared>(offsets.size()); + memcpy(vec_offsets->data(), offsets_ptr, sizeof(int32_t) * offsets.size()); + + int per_vector_size = static_cast(cdfs.size() / cdf_num); + auto vec_cdfs = std::make_shared>>(cdf_num); + auto cdfs_raw = cdfs.unchecked<2>(); + for (int i = 0; i < cdf_num; i++) { + std::vector t(per_vector_size); + memcpy(t.data(), cdfs_raw.data(i, 0), sizeof(int32_t) * per_vector_size); + vec_cdfs->at(i) = t; + } + + int cdf_idx = m_encoder0->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); + m_encoder1->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); + return cdf_idx; +} + +void RansEncoder::empty_cdf_buffer() +{ + m_encoder0->empty_cdf_buffer(); + m_encoder1->empty_cdf_buffer(); +} + +void RansEncoder::flush() +{ + m_encoder0->flush(); + m_encoder1->flush(); +} + +py::array_t RansEncoder::get_encoded_stream() +{ + if (m_use_two_encoders) { + auto result0 = m_encoder0->get_encoded_stream(); + int nbytes0 = static_cast(result0->size()); + auto result1 = m_encoder1->get_encoded_stream(); + int nbytes1 = static_cast(result1->size()); + + int identical_bytes = 0; + int check_bytes = std::min(nbytes0, nbytes1); + check_bytes = std::min(check_bytes, 8); + for (int i = 0; i < check_bytes; i++) { + if (result0->at(nbytes0 - 1 - i) != 0) { + break; + } + if (result1->at(nbytes1 - 1 - i) != 0) { + break; + } + identical_bytes++; + } + if (identical_bytes == 0 && result0->at(nbytes0 - 1) == result1->at(nbytes1 - 1)) { + identical_bytes = 1; + } + + py::array_t stream(nbytes0 + nbytes1 - identical_bytes); + py::buffer_info stream_buf = stream.request(); + uint8_t* stream_ptr = static_cast(stream_buf.ptr); + + std::copy(result0->begin(), result0->end(), stream_ptr); + std::reverse_copy(result1->begin(), result1->end() - identical_bytes, stream_ptr + nbytes0); + return stream; + } + + auto result0 = m_encoder0->get_encoded_stream(); + int nbytes0 = static_cast(result0->size()); + + py::array_t stream(nbytes0); + py::buffer_info stream_buf = stream.request(); + uint8_t* stream_ptr = static_cast(stream_buf.ptr); + + std::copy(result0->begin(), result0->end(), stream_ptr); + return stream; +} + +void RansEncoder::reset() +{ + m_encoder0->reset(); + m_encoder1->reset(); +} + +void RansEncoder::set_use_two_encoders(bool b) +{ + m_use_two_encoders = b; +} + +bool RansEncoder::get_use_two_encoders() +{ + return m_use_two_encoders; +} + +RansDecoder::RansDecoder() +{ + m_decoder0 = std::make_shared(); + m_decoder1 = std::make_shared(); +} + +void RansDecoder::set_stream(const py::array_t& encoded) +{ + py::buffer_info encoded_buf = encoded.request(); + const uint8_t* encoded_ptr = static_cast(encoded_buf.ptr); + const int encoded_size = static_cast(encoded.size()); + auto stream0 = std::make_shared>(encoded.size()); + std::copy(encoded_ptr, encoded_ptr + encoded_size, stream0->data()); + m_decoder0->set_stream(stream0); + if (m_use_two_decoders) { + auto stream1 = std::make_shared>(encoded.size()); + std::reverse_copy(encoded_ptr, encoded_ptr + encoded_size, stream1->data()); + m_decoder1->set_stream(stream1); + } +} + +void RansDecoder::decode_y(const py::array_t& indexes, const int cdf_group_index) +{ + py::buffer_info indexes_buf = indexes.request(); + uint8_t* indexes_ptr = static_cast(indexes_buf.ptr); + + int indexSize = static_cast(indexes.size()); + if (m_use_two_decoders) { + int indexSize0 = indexSize / 2; + int indexSize1 = indexSize - indexSize0; + + auto vec_indexes0 = std::make_shared>(indexSize0); + std::copy(indexes_ptr, indexes_ptr + indexSize0, vec_indexes0->data()); + m_decoder0->decode_y(vec_indexes0, cdf_group_index); + + auto vec_indexes1 = std::make_shared>(indexSize1); + std::copy(indexes_ptr + indexSize0, indexes_ptr + indexSize, vec_indexes1->data()); + m_decoder1->decode_y(vec_indexes1, cdf_group_index); + } else { + auto vec_indexes0 = std::make_shared>(indexSize); + std::copy(indexes_ptr, indexes_ptr + indexSize, vec_indexes0->data()); + m_decoder0->decode_y(vec_indexes0, cdf_group_index); + } +} + +py::array_t RansDecoder::decode_and_get_y(const py::array_t& indexes, + const int cdf_group_index) +{ + decode_y(indexes, cdf_group_index); + return get_decoded_tensor(); +} + +void RansDecoder::decode_z(const int total_size, const int cdf_group_index, const int start_offset, + const int per_channel_size) +{ + if (m_use_two_decoders) { + int symbolSize0 = total_size / 2; + int symbolSize1 = total_size - symbolSize0; + int channel_half = symbolSize0 / per_channel_size; + m_decoder0->decode_z(symbolSize0, cdf_group_index, start_offset, per_channel_size); + m_decoder1->decode_z(symbolSize1, cdf_group_index, start_offset + channel_half, + per_channel_size); + } else { + m_decoder0->decode_z(total_size, cdf_group_index, start_offset, per_channel_size); + } +} + +py::array_t RansDecoder::get_decoded_tensor() +{ + if (m_use_two_decoders) { + auto result0 = m_decoder0->get_decoded_tensor(); + const int total_size0 = static_cast(result0->size()); + + auto result1 = m_decoder1->get_decoded_tensor(); + const int total_size1 = static_cast(result1->size()); + py::array_t output(total_size0 + total_size1); + py::buffer_info buf = output.request(); + int8_t* buf_ptr = static_cast(buf.ptr); + std::copy(result0->begin(), result0->end(), buf_ptr); + std::copy(result1->begin(), result1->end(), buf_ptr + total_size0); + + return output; + } + + auto result0 = m_decoder0->get_decoded_tensor(); + const int total_size0 = static_cast(result0->size()); + + py::array_t output(total_size0); + py::buffer_info buf = output.request(); + int8_t* buf_ptr = static_cast(buf.ptr); + std::copy(result0->begin(), result0->end(), buf_ptr); + + return output; +} + +int RansDecoder::add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const py::array_t& offsets) +{ + py::buffer_info cdfs_sizes_buf = cdfs_sizes.request(); + py::buffer_info offsets_buf = offsets.request(); + int32_t* cdfs_sizes_ptr = static_cast(cdfs_sizes_buf.ptr); + int32_t* offsets_ptr = static_cast(offsets_buf.ptr); + + int cdf_num = static_cast(cdfs_sizes.size()); + auto vec_cdfs_sizes = std::make_shared>(cdf_num); + memcpy(vec_cdfs_sizes->data(), cdfs_sizes_ptr, sizeof(int32_t) * cdf_num); + auto vec_offsets = std::make_shared>(offsets.size()); + memcpy(vec_offsets->data(), offsets_ptr, sizeof(int32_t) * offsets.size()); + + int per_vector_size = static_cast(cdfs.size() / cdf_num); + auto vec_cdfs = std::make_shared>>(cdf_num); + auto cdfs_raw = cdfs.unchecked<2>(); + for (int i = 0; i < cdf_num; i++) { + std::vector t(per_vector_size); + memcpy(t.data(), cdfs_raw.data(i, 0), sizeof(int32_t) * per_vector_size); + vec_cdfs->at(i) = t; + } + int cdf_idx = m_decoder0->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); + m_decoder1->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); + return cdf_idx; +} + +void RansDecoder::empty_cdf_buffer() +{ + m_decoder0->empty_cdf_buffer(); + m_decoder1->empty_cdf_buffer(); +} + +void RansDecoder::set_use_two_decoders(bool b) +{ + m_use_two_decoders = b; +} + +bool RansDecoder::get_use_two_decoders() +{ + return m_use_two_decoders; +} + +std::vector pmf_to_quantized_cdf(const std::vector& pmf, int precision) +{ + /* NOTE(begaintj): ported from `ryg_rans` public implementation. Not optimal + * although it's only run once per model after training. See TF/compression + * implementation for an optimized version. */ + + std::vector cdf(pmf.size() + 1); + cdf[0] = 0; /* freq 0 */ + + std::transform(pmf.begin(), pmf.end(), cdf.begin() + 1, [=](float p) { + return static_cast(std::round(p * (1 << precision)) + 0.5); + }); + + const uint32_t total = std::accumulate(cdf.begin(), cdf.end(), 0); + + std::transform(cdf.begin(), cdf.end(), cdf.begin(), [precision, total](uint32_t p) { + return static_cast((((1ull << precision) * p) / total)); + }); + + std::partial_sum(cdf.begin(), cdf.end(), cdf.begin()); + cdf.back() = 1 << precision; + + for (int i = 0; i < static_cast(cdf.size() - 1); ++i) { + if (cdf[i] == cdf[i + 1]) { + /* Try to steal frequency from low-frequency symbols */ + uint32_t best_freq = ~0u; + int best_steal = -1; + for (int j = 0; j < static_cast(cdf.size()) - 1; ++j) { + uint32_t freq = cdf[j + 1] - cdf[j]; + if (freq > 1 && freq < best_freq) { + best_freq = freq; + best_steal = j; + } + } + + assert(best_steal != -1); + + if (best_steal < i) { + for (int j = best_steal + 1; j <= i; ++j) { + cdf[j]--; + } + } else { + assert(best_steal > i); + for (int j = i + 1; j <= best_steal; ++j) { + cdf[j]++; + } + } + } + } + + assert(cdf[0] == 0); + assert(cdf.back() == (1u << precision)); + for (int i = 0; i < static_cast(cdf.size()) - 1; ++i) { + assert(cdf[i + 1] > cdf[i]); + } + + return cdf; +} + +PYBIND11_MODULE(MLCodec_extensions_cpp, m) +{ + py::class_(m, "RansEncoder") + .def(py::init<>()) + .def("encode_y", &RansEncoder::encode_y) + .def("encode_z", &RansEncoder::encode_z) + .def("flush", &RansEncoder::flush) + .def("get_encoded_stream", &RansEncoder::get_encoded_stream) + .def("reset", &RansEncoder::reset) + .def("add_cdf", &RansEncoder::add_cdf) + .def("empty_cdf_buffer", &RansEncoder::empty_cdf_buffer) + .def("set_use_two_encoders", &RansEncoder::set_use_two_encoders) + .def("get_use_two_encoders", &RansEncoder::get_use_two_encoders); + + py::class_(m, "RansDecoder") + .def(py::init<>()) + .def("set_stream", &RansDecoder::set_stream) + .def("decode_y", &RansDecoder::decode_y) + .def("decode_and_get_y", &RansDecoder::decode_and_get_y) + .def("decode_z", &RansDecoder::decode_z) + .def("get_decoded_tensor", &RansDecoder::get_decoded_tensor) + .def("add_cdf", &RansDecoder::add_cdf) + .def("empty_cdf_buffer", &RansDecoder::empty_cdf_buffer) + .def("set_use_two_decoders", &RansDecoder::set_use_two_decoders) + .def("get_use_two_decoders", &RansDecoder::get_use_two_decoders); + + m.def("pmf_to_quantized_cdf", &pmf_to_quantized_cdf, "Return quantized CDF for a given PMF"); +} diff --git a/DCVC-family/DCVC-RT/src/cpp/py_rans/py_rans.h b/DCVC-family/DCVC-RT/src/cpp/py_rans/py_rans.h new file mode 100644 index 0000000..c7d223a --- /dev/null +++ b/DCVC-family/DCVC-RT/src/cpp/py_rans/py_rans.h @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "rans.h" +#include + +#include +#include +#include + +namespace py = pybind11; + +// the classes in this file only perform the type conversion +// from python type (numpy) to C++ type (vector) +class RansEncoder { +public: + RansEncoder(); + + RansEncoder(const RansEncoder&) = delete; + RansEncoder(RansEncoder&&) = delete; + RansEncoder& operator=(const RansEncoder&) = delete; + RansEncoder& operator=(RansEncoder&&) = delete; + + void encode_y(const py::array_t& symbols, const int cdf_group_index); + void encode_z(const py::array_t& symbols, const int cdf_group_index, + const int start_offset, const int per_channel_size); + void flush(); + py::array_t get_encoded_stream(); + void reset(); + int add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const py::array_t& offsets); + void empty_cdf_buffer(); + void set_use_two_encoders(bool b); + bool get_use_two_encoders(); + +private: + std::shared_ptr m_encoder0; + std::shared_ptr m_encoder1; + bool m_use_two_encoders{ false }; +}; + +class RansDecoder { +public: + RansDecoder(); + + RansDecoder(const RansDecoder&) = delete; + RansDecoder(RansDecoder&&) = delete; + RansDecoder& operator=(const RansDecoder&) = delete; + RansDecoder& operator=(RansDecoder&&) = delete; + + void set_stream(const py::array_t&); + + void decode_y(const py::array_t& indexes, const int cdf_group_index); + py::array_t decode_and_get_y(const py::array_t& indexes, const int cdf_group_index); + void decode_z(const int total_size, const int cdf_group_index, const int start_offset, + const int per_channel_size); + py::array_t get_decoded_tensor(); + int add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const py::array_t& offsets); + void empty_cdf_buffer(); + void set_use_two_decoders(bool b); + bool get_use_two_decoders(); + +private: + std::shared_ptr m_decoder0; + std::shared_ptr m_decoder1; + bool m_use_two_decoders{ false }; +}; + +std::vector pmf_to_quantized_cdf(const std::vector& pmf, int precision); diff --git a/DCVC-family/DCVC-RT/src/cpp/py_rans/rans.cpp b/DCVC-family/DCVC-RT/src/cpp/py_rans/rans.cpp new file mode 100644 index 0000000..11eb342 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/cpp/py_rans/rans.cpp @@ -0,0 +1,534 @@ +/* Copyright 2020 InterDigital Communications, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Rans64 extensions from: + * https://fgiesen.wordpress.com/2015/12/21/rans-in-practice/ + * Unbounded range coding from: + * https://github.com/tensorflow/compression/blob/master/tensorflow_compression/cc/kernels/unbounded_index_range_coding_kernels.cc + **/ + +#include "rans.h" + +#include +#include +#include + +constexpr uint16_t bypass_precision = 2; /* number of bits in bypass mode */ +constexpr uint16_t max_bypass_val = (1 << bypass_precision) - 1; + +inline void RansEncPutBits(RansState& r, uint8_t*& ptr, uint32_t val) +{ + RansAssert(bypass_precision <= 8); + RansAssert(val < (1u << bypass_precision)); + + constexpr uint32_t freq = 1 << (SCALE_BITS - bypass_precision); + constexpr uint32_t x_max = freq << ENC_RENORM_SHIFT_BITS; + while (r >= x_max) { + *(--ptr) = static_cast(r & 0xff); + r >>= 8; + } + + r = (r << bypass_precision) | val; +} + +inline uint32_t RansDecGetBits(RansState& r, uint8_t*& ptr) +{ + uint32_t val = r & ((1u << bypass_precision) - 1); + + /* Re-normalize */ + r = r >> bypass_precision; + if (r < RANS_BYTE_L) { + r = (r << 8) | *ptr++; + RansAssert(r >= RANS_BYTE_L); + } + + return val; +} + +RansEncoderLib::RansEncoderLib() +{ + _stream = std::make_shared>(); +} + +int RansEncoderLib::add_cdf(const std::shared_ptr>> cdfs, + const std::shared_ptr> cdfs_sizes, + const std::shared_ptr> offsets) +{ + + auto ransSymbols = std::make_shared>>(cdfs->size()); + for (int i = 0; i < static_cast(cdfs->size()); i++) { + const int32_t* cdf = cdfs->at(i).data(); + std::vector ransSym(cdfs->at(i).size()); + const int ransSize = static_cast(ransSym.size() - 1); + for (int j = 0; j < ransSize; j++) { + ransSym[j] = RansSymbol( + { static_cast(cdf[j]), static_cast(cdf[j + 1] - cdf[j]) }); + } + ransSymbols->at(i) = ransSym; + } + + _ransSymbols.push_back(ransSymbols); + _cdfs_sizes.push_back(cdfs_sizes); + _offsets.push_back(offsets); + return static_cast(_ransSymbols.size()) - 1; +} + +void RansEncoderLib::empty_cdf_buffer() +{ + _ransSymbols.clear(); + _cdfs_sizes.clear(); + _offsets.clear(); +} + +FORCE_INLINE void RansEncoderLib::encode_one_symbol(uint8_t*& ptr, RansState& rans, const int32_t symbol, + const int32_t cdf_size, const int32_t offset, + const std::vector& ransSymbols) +{ + const int32_t max_value = cdf_size - 2; + int32_t value = symbol - offset; + + uint32_t raw_val = 0; + if (value < 0) { + raw_val = -2 * value - 1; + value = max_value; + } else if (value >= max_value) { + raw_val = 2 * (value - max_value); + value = max_value; + } + + if (value == max_value) { + std::vector bypassBins; + bypassBins.reserve(20); + /* Determine the number of bypasses (in bypass_precision size) needed to + * encode the raw value. */ + int32_t n_bypass = 0; + while ((raw_val >> (n_bypass * bypass_precision)) != 0) { + ++n_bypass; + } + + /* Encode number of bypasses */ + int32_t val = n_bypass; + while (val >= max_bypass_val) { + bypassBins.push_back(max_bypass_val); + val -= max_bypass_val; + } + bypassBins.push_back(static_cast(val)); + + /* Encode raw value */ + for (int32_t j = 0; j < n_bypass; ++j) { + const int32_t val1 = (raw_val >> (j * bypass_precision)) & max_bypass_val; + bypassBins.push_back(static_cast(val1)); + } + + for (auto it = bypassBins.rbegin(); it < bypassBins.rend(); it++) { + RansEncPutBits(rans, ptr, *it); + } + } + RansEncPut(rans, ptr, ransSymbols[value].start, ransSymbols[value].range); +} + +void RansEncoderLib::encode_y(const std::shared_ptr> symbols, + const int cdf_group_index) +{ + PendingTask p; + p.workType = WorkType::EncodeDecodeY; + p.symbols_y = symbols; + p.cdf_group_index = cdf_group_index; + m_pendingEncodingList.push_back(p); +} + +void RansEncoderLib::encode_z(const std::shared_ptr> symbols, + const int cdf_group_index, const int start_offset, + const int per_channel_size) +{ + PendingTask p; + p.workType = WorkType::EncodeDecodeZ; + p.symbols_z = symbols; + p.cdf_group_index = cdf_group_index; + p.start_offset = start_offset; + p.per_channel_size = per_channel_size; + m_pendingEncodingList.push_back(p); +} +#include +FORCE_INLINE void RansEncoderLib::encode_y_internal(uint8_t*& ptr, RansState& rans, + const std::shared_ptr> symbols, + const int cdf_group_index) +{ + // backward loop on symbols from the end; + const int16_t* symbols_ptr = symbols->data(); + const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); + const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); + const int symbol_size = static_cast(symbols->size()); + + for (int i = symbol_size - 1; i >= 0; i--) { + const int32_t combined_symbol = symbols_ptr[i]; + const int32_t cdf_idx = combined_symbol & 0xff; + const int32_t s = combined_symbol >> 8; + encode_one_symbol(ptr, rans, s, cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx], + _ransSymbols[cdf_group_index]->at(cdf_idx)); + } +} + +FORCE_INLINE void RansEncoderLib::encode_z_internal(uint8_t*& ptr, RansState& rans, + const std::shared_ptr> symbols, + const int cdf_group_index, const int start_offset, + const int per_channel_size) +{ + // backward loop on symbols from the end; + const int8_t* symbols_ptr = symbols->data(); + const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); + const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); + const int symbol_size = static_cast(symbols->size()); + + for (int i = symbol_size - 1; i >= 0; i--) { + const int32_t cdf_idx = i / per_channel_size + start_offset; + encode_one_symbol(ptr, rans, symbols_ptr[i], cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx], + _ransSymbols[cdf_group_index]->at(cdf_idx)); + } +} + +void RansEncoderLib::flush() +{ + RansState rans; + RansEncInit(rans); + + int32_t total_symbol_size = 0; + for (auto it = m_pendingEncodingList.begin(); it != m_pendingEncodingList.end(); it++) { + if (it->workType == WorkType::EncodeDecodeY) { + total_symbol_size += static_cast(it->symbols_y->size()); + } else if (it->workType == WorkType::EncodeDecodeZ) { + total_symbol_size += static_cast(it->symbols_z->size()); + } + } + + if (total_symbol_size == 0) { + _stream->resize(0); + return; + } + + uint8_t* output = new uint8_t[total_symbol_size]; // too much space ? + uint8_t* ptrEnd = output + total_symbol_size; + uint8_t* ptr = ptrEnd; + assert(ptr != nullptr); + + for (auto it = m_pendingEncodingList.rbegin(); it != m_pendingEncodingList.rend(); it++) { + PendingTask p = *it; + if (p.workType == WorkType::EncodeDecodeY) { + encode_y_internal(ptr, rans, p.symbols_y, p.cdf_group_index); + } else if (p.workType == WorkType::EncodeDecodeZ) { + encode_z_internal(ptr, rans, p.symbols_z, p.cdf_group_index, p.start_offset, + p.per_channel_size); + } + } + + RansEncFlush(rans, ptr); + + const int nbytes = static_cast(std::distance(ptr, ptrEnd)); + + _stream->resize(nbytes); + memcpy(_stream->data(), ptr, nbytes); + delete[] output; +} + +std::shared_ptr> RansEncoderLib::get_encoded_stream() +{ + return _stream; +} + +void RansEncoderLib::reset() +{ + m_pendingEncodingList.clear(); + _stream->clear(); +} + +RansEncoderLibMultiThread::RansEncoderLibMultiThread() + : RansEncoderLib() + , m_finish(false) + , m_result_ready(false) +{ + m_thread = std::thread(&RansEncoderLibMultiThread::worker, this); +} +RansEncoderLibMultiThread::~RansEncoderLibMultiThread() +{ + { + std::lock_guard lk(m_mutex_pending); + std::lock_guard lk1(m_mutex_result); + m_finish = true; + } + m_cv_pending.notify_one(); + m_cv_result.notify_one(); + m_thread.join(); +} + +void RansEncoderLibMultiThread::flush() +{ + PendingTask p; + p.workType = WorkType::Flush; + { + std::unique_lock lk(m_mutex_pending); + m_pending.push_back(p); + } + m_cv_pending.notify_one(); +} + +std::shared_ptr> RansEncoderLibMultiThread::get_encoded_stream() +{ + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + return RansEncoderLib::get_encoded_stream(); +} + +void RansEncoderLibMultiThread::reset() +{ + RansEncoderLib::reset(); + std::lock_guard lk(m_mutex_result); + m_result_ready = false; +} + +void RansEncoderLibMultiThread::worker() +{ + while (!m_finish) { + std::unique_lock lk(m_mutex_pending); + m_cv_pending.wait(lk, [this] { return m_pending.size() > 0 || m_finish; }); + if (m_finish) { + lk.unlock(); + break; + } + if (m_pending.size() == 0) { + lk.unlock(); + // std::cout << "contine in worker" << std::endl; + continue; + } + while (m_pending.size() > 0) { + auto p = m_pending.front(); + m_pending.pop_front(); + lk.unlock(); + if (p.workType == WorkType::Flush) { + RansEncoderLib::flush(); + { + std::lock_guard lk_result(m_mutex_result); + m_result_ready = true; + } + m_cv_result.notify_one(); + } + lk.lock(); + } + lk.unlock(); + } +} + +void RansDecoderLib::set_stream(const std::shared_ptr> encoded) +{ + _stream = encoded; + _ptr8 = (uint8_t*)(_stream->data()); + RansDecInit(_rans, _ptr8); +} + +int RansDecoderLib::add_cdf(const std::shared_ptr>> cdfs, + const std::shared_ptr> cdfs_sizes, + const std::shared_ptr> offsets) +{ + _cdfs.push_back(cdfs); + _cdfs_sizes.push_back(cdfs_sizes); + _offsets.push_back(offsets); + return static_cast(_cdfs.size()) - 1; +} + +void RansDecoderLib::empty_cdf_buffer() +{ + _cdfs.clear(); + _cdfs_sizes.clear(); + _offsets.clear(); +} + +FORCE_INLINE int8_t RansDecoderLib::decode_one_symbol(const int32_t* cdf, const int32_t cdf_size, + const int32_t offset) +{ + const int32_t max_value = cdf_size - 2; + const int32_t cum_freq = static_cast(RansDecGet(_rans)); + + int s = 1; + while (cdf[s++] <= cum_freq) { + } + s -= 2; + + RansDecAdvance(_rans, _ptr8, cdf[s], cdf[s + 1] - cdf[s]); + + int32_t value = static_cast(s); + + if (value == max_value) { + /* Bypass decoding mode */ + int32_t val = RansDecGetBits(_rans, _ptr8); + int32_t n_bypass = val; + + while (val == max_bypass_val) { + val = RansDecGetBits(_rans, _ptr8); + n_bypass += val; + } + + int32_t raw_val = 0; + for (int j = 0; j < n_bypass; ++j) { + val = RansDecGetBits(_rans, _ptr8); + raw_val |= val << (j * bypass_precision); + } + value = raw_val >> 1; + if (raw_val & 1) { + value = -value - 1; + } else { + value += max_value; + } + } + + return static_cast(value + offset); +} + +void RansDecoderLib::decode_y(const std::shared_ptr> indexes, + const int cdf_group_index) +{ + int index_size = static_cast(indexes->size()); + m_decoded = std::make_shared>(index_size); + + int8_t* outout_ptr = m_decoded->data(); + const uint8_t* indexes_ptr = indexes->data(); + const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); + const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); + const auto& cdfs = _cdfs[cdf_group_index]; + for (int i = 0; i < index_size; ++i) { + const int32_t cdf_idx = indexes_ptr[i]; + outout_ptr[i] = decode_one_symbol(cdfs->at(cdf_idx).data(), cdfs_sizes_ptr[cdf_idx], + offsets_ptr[cdf_idx]); + } +} + +void RansDecoderLib::decode_z(const int total_size, const int cdf_group_index, + const int start_offset, const int per_channel_size) +{ + m_decoded = std::make_shared>(total_size); + + int8_t* outout_ptr = m_decoded->data(); + const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); + const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); + const auto& cdfs = _cdfs[cdf_group_index]; + for (int i = 0; i < total_size; ++i) { + const int32_t cdf_idx = i / per_channel_size + start_offset; + outout_ptr[i] = decode_one_symbol(cdfs->at(cdf_idx).data(), cdfs_sizes_ptr[cdf_idx], + offsets_ptr[cdf_idx]); + } +} + +std::shared_ptr> RansDecoderLib::get_decoded_tensor() +{ + return m_decoded; +} + +RansDecoderLibMultiThread::RansDecoderLibMultiThread() + : RansDecoderLib() + , m_finish(false) + , m_result_ready(false) +{ + m_thread = std::thread(&RansDecoderLibMultiThread::worker, this); +} + +RansDecoderLibMultiThread::~RansDecoderLibMultiThread() +{ + { + std::lock_guard lk(m_mutex_pending); + std::lock_guard lk1(m_mutex_result); + m_finish = true; + } + m_cv_pending.notify_one(); + m_cv_result.notify_one(); + m_thread.join(); +} + +void RansDecoderLibMultiThread::decode_y(const std::shared_ptr> indexes, + const int cdf_group_index) +{ + { + std::lock_guard lk(m_mutex_result); + m_result_ready = false; + } + PendingTask p; + p.workType = WorkType::EncodeDecodeY; + p.indexes = indexes; + p.cdf_group_index = cdf_group_index; + { + std::unique_lock lk(m_mutex_pending); + m_pending.push_back(p); + } + m_cv_pending.notify_one(); +} + +void RansDecoderLibMultiThread::decode_z(const int total_size, const int cdf_group_index, + const int start_offset, const int per_channel_size) +{ + { + std::lock_guard lk(m_mutex_result); + m_result_ready = false; + } + PendingTask p; + p.workType = WorkType::EncodeDecodeZ; + p.total_size = total_size; + p.cdf_group_index = cdf_group_index; + p.start_offset = start_offset; + p.per_channel_size = per_channel_size; + { + std::unique_lock lk(m_mutex_pending); + m_pending.push_back(p); + } + m_cv_pending.notify_one(); +} + +std::shared_ptr> RansDecoderLibMultiThread::get_decoded_tensor() +{ + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + return RansDecoderLib::get_decoded_tensor(); +} + +void RansDecoderLibMultiThread::worker() +{ + while (!m_finish) { + std::unique_lock lk(m_mutex_pending); + m_cv_pending.wait(lk, [this] { return m_pending.size() > 0 || m_finish; }); + if (m_finish) { + lk.unlock(); + break; + } + if (m_pending.size() == 0) { + lk.unlock(); + // std::cout << "contine in worker" << std::endl; + continue; + } + while (m_pending.size() > 0) { + auto p = m_pending.front(); + m_pending.pop_front(); + lk.unlock(); + if (p.workType == WorkType::EncodeDecodeY) { + RansDecoderLib::decode_y(p.indexes, p.cdf_group_index); + } else if (p.workType == WorkType::EncodeDecodeZ) { + RansDecoderLib::decode_z(p.total_size, p.cdf_group_index, p.start_offset, + p.per_channel_size); + } + { + std::lock_guard lk_result(m_mutex_result); + m_result_ready = true; + } + m_cv_result.notify_one(); + lk.lock(); + } + lk.unlock(); + } +} diff --git a/DCVC-family/DCVC-RT/src/cpp/py_rans/rans.h b/DCVC-family/DCVC-RT/src/cpp/py_rans/rans.h new file mode 100644 index 0000000..995dfee --- /dev/null +++ b/DCVC-family/DCVC-RT/src/cpp/py_rans/rans.h @@ -0,0 +1,201 @@ +/* Copyright 2020 InterDigital Communications, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" + #pragma GCC diagnostic ignored "-Wsign-compare" +#endif + +#ifdef _MSC_VER + #pragma warning(disable : 4244) +#endif + +#include "rans_byte.h" + +#ifdef _MSC_VER + #pragma warning(default : 4244) +#endif + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER + #define FORCE_INLINE __forceinline +#endif + +#ifdef __GNUC__ + #define FORCE_INLINE __attribute__((always_inline)) inline +#endif + +struct RansSymbol { + uint16_t start; + uint16_t range; // range for normal coding and 0 for bypass coding +}; + +enum class WorkType { + EncodeDecodeY, + EncodeDecodeZ, + Flush, +}; + +struct PendingTask { + WorkType workType; + std::shared_ptr> symbols_y; + std::shared_ptr> symbols_z; + std::shared_ptr> indexes; + int total_size{ 0 }; + int cdf_group_index{ 0 }; + int start_offset{ 0 }; + int per_channel_size{ 0 }; +}; + +/* NOTE: Warning, we buffer everything for now... In case of large files we + * should split the bitstream into chunks... Or for a memory-bounded encoder + **/ +class RansEncoderLib { +public: + RansEncoderLib(); + virtual ~RansEncoderLib() = default; + + RansEncoderLib(const RansEncoderLib&) = delete; + RansEncoderLib(RansEncoderLib&&) = delete; + RansEncoderLib& operator=(const RansEncoderLib&) = delete; + RansEncoderLib& operator=(RansEncoderLib&&) = delete; + + void encode_y(const std::shared_ptr> symbols, const int cdf_group_index); + void encode_z(const std::shared_ptr> symbols, const int cdf_group_index, + const int start_offset, const int per_channel_size); + + FORCE_INLINE void encode_y_internal(uint8_t*& ptr, RansState& rans, + const std::shared_ptr> symbols, + const int cdf_group_index); + FORCE_INLINE void encode_z_internal(uint8_t*& ptr, RansState& rans, + const std::shared_ptr> symbols, + const int cdf_group_index, const int start_offset, + const int per_channel_size); + FORCE_INLINE void encode_one_symbol(uint8_t*& ptr, RansState& rans, const int32_t symbol, + const int32_t cdf_size, const int32_t offset, + const std::vector& ransSymbols); + virtual void flush(); + virtual std::shared_ptr> get_encoded_stream(); + virtual void reset(); + virtual int add_cdf(const std::shared_ptr>> cdfs, + const std::shared_ptr> cdfs_sizes, + const std::shared_ptr> offsets); + virtual void empty_cdf_buffer(); + +private: + std::shared_ptr> _stream; + + std::vector>>> _ransSymbols; + std::vector>> _cdfs_sizes; + std::vector>> _offsets; + + std::list m_pendingEncodingList; +}; + +class RansEncoderLibMultiThread : public RansEncoderLib { +public: + RansEncoderLibMultiThread(); + virtual ~RansEncoderLibMultiThread(); + virtual void flush() override; + virtual std::shared_ptr> get_encoded_stream() override; + virtual void reset() override; + + void worker(); + +private: + bool m_finish; + bool m_result_ready; + std::thread m_thread; + std::mutex m_mutex_result; + std::mutex m_mutex_pending; + std::condition_variable m_cv_pending; + std::condition_variable m_cv_result; + std::list m_pending; +}; + +class RansDecoderLib { +public: + RansDecoderLib() {} + virtual ~RansDecoderLib() = default; + + RansDecoderLib(const RansDecoderLib&) = delete; + RansDecoderLib(RansDecoderLib&&) = delete; + RansDecoderLib& operator=(const RansDecoderLib&) = delete; + RansDecoderLib& operator=(RansDecoderLib&&) = delete; + + virtual void set_stream(const std::shared_ptr> encoded); + + FORCE_INLINE int8_t decode_one_symbol(const int32_t* cdf, const int32_t cdf_size, + const int32_t offset); + + virtual void decode_y(const std::shared_ptr> indexes, + const int cdf_group_index); + virtual void decode_z(const int total_size, const int cdf_group_index, const int start_offset, + const int per_channel_size); + + virtual std::shared_ptr> get_decoded_tensor(); + + virtual int add_cdf(const std::shared_ptr>> cdfs, + const std::shared_ptr> cdfs_sizes, + const std::shared_ptr> offsets); + virtual void empty_cdf_buffer(); + +private: + RansState _rans; + uint8_t* _ptr8; + std::shared_ptr> _stream; + std::shared_ptr> m_decoded; + + std::vector>>> _cdfs; + std::vector>> _cdfs_sizes; + std::vector>> _offsets; +}; + +class RansDecoderLibMultiThread : public RansDecoderLib { +public: + RansDecoderLibMultiThread(); + virtual ~RansDecoderLibMultiThread(); + + virtual void decode_y(const std::shared_ptr> indexes, + const int cdf_group_index) override; + + virtual void decode_z(const int total_size, const int cdf_group_index, const int start_offset, + const int per_channel_size) override; + + virtual std::shared_ptr> get_decoded_tensor() override; + + void worker(); + +private: + bool m_finish; + bool m_result_ready; + std::thread m_thread; + std::mutex m_mutex_result; + std::mutex m_mutex_pending; + std::condition_variable m_cv_pending; + std::condition_variable m_cv_result; + std::list m_pending; +}; \ No newline at end of file diff --git a/src/cpp/py_rans/rans_byte.h b/DCVC-family/DCVC-RT/src/cpp/py_rans/rans_byte.h similarity index 100% rename from src/cpp/py_rans/rans_byte.h rename to DCVC-family/DCVC-RT/src/cpp/py_rans/rans_byte.h diff --git a/DCVC-family/DCVC-RT/src/cpp/setup.py b/DCVC-family/DCVC-RT/src/cpp/setup.py new file mode 100644 index 0000000..7e1b036 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/cpp/setup.py @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import glob +import sys +from setuptools import setup +from pybind11.setup_helpers import Pybind11Extension, build_ext + + +if sys.platform == "win32": + extra_compile_args = ['/std:c++17', '/O2', '/W4', '/WX', '/wd4100'] + extra_link_args = [] +else: + extra_compile_args = ['-std=c++17', '-O3', '-fPIC', '-Wall', '-Wextra', '-Werror'] + extra_link_args = [] + + +setup( + name="MLCodec_extensions_cpp", + ext_modules=[ + Pybind11Extension( + name='MLCodec_extensions_cpp', + sources=glob.glob('py_rans/*.cpp'), + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, + ), + ], + cmdclass={"build_ext": build_ext}, + zip_safe=False, + python_requires=">=3.12", +) diff --git a/src/layers/cuda_inference.py b/DCVC-family/DCVC-RT/src/layers/cuda_inference.py similarity index 100% rename from src/layers/cuda_inference.py rename to DCVC-family/DCVC-RT/src/layers/cuda_inference.py diff --git a/DCVC-family/DCVC-RT/src/layers/extensions/inference/bind.cpp b/DCVC-family/DCVC-RT/src/layers/extensions/inference/bind.cpp new file mode 100644 index 0000000..0bc8e24 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/layers/extensions/inference/bind.cpp @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "def.h" +#include + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) +{ + m.def("process_with_mask_cuda", &process_with_mask_cuda); + m.def("combine_for_reading_2x_cuda", &combine_for_reading_2x_cuda); + m.def("restore_y_2x_cuda", &restore_y_2x_cuda); + m.def("restore_y_4x_cuda", &restore_y_4x_cuda); + m.def("build_index_dec_cuda", &build_index_dec_cuda); + m.def("build_index_enc_cuda", &build_index_enc_cuda); + m.def("bias_quant_cuda", &bias_quant_cuda); + m.def("round_and_to_int8_cuda", &round_and_to_int8_cuda); + m.def("clamp_reciprocal_with_quant_cuda", &clamp_reciprocal_with_quant_cuda); + m.def("add_and_multiply_cuda", &add_and_multiply_cuda); + m.def("bias_pixel_shuffle_8_cuda", &bias_pixel_shuffle_8_cuda); + m.def("replicate_pad_cuda", &replicate_pad_cuda); + m.def("bias_wsilu_depthwise_conv2d_cuda", &bias_wsilu_depthwise_conv2d_cuda); + + py::class_(m, "DepthConvProxy") + .def(py::init<>()) + .def("set_param", &DepthConvProxy::set_param) + .def("set_param_with_adaptor", &DepthConvProxy::set_param_with_adaptor) + .def("forward", &DepthConvProxy::forward) + .def("forward_with_quant_step", &DepthConvProxy::forward_with_quant_step) + .def("forward_with_cat", &DepthConvProxy::forward_with_cat); + + py::class_(m, "SubpelConv2xProxy") + .def(py::init<>()) + .def("set_param", &SubpelConv2xProxy::set_param) + .def("forward", &SubpelConv2xProxy::forward) + .def("forward_with_cat", &SubpelConv2xProxy::forward_with_cat); +} diff --git a/src/layers/extensions/inference/common.h b/DCVC-family/DCVC-RT/src/layers/extensions/inference/common.h similarity index 100% rename from src/layers/extensions/inference/common.h rename to DCVC-family/DCVC-RT/src/layers/extensions/inference/common.h diff --git a/src/layers/extensions/inference/def.h b/DCVC-family/DCVC-RT/src/layers/extensions/inference/def.h similarity index 100% rename from src/layers/extensions/inference/def.h rename to DCVC-family/DCVC-RT/src/layers/extensions/inference/def.h diff --git a/src/layers/extensions/inference/impl.cpp b/DCVC-family/DCVC-RT/src/layers/extensions/inference/impl.cpp similarity index 100% rename from src/layers/extensions/inference/impl.cpp rename to DCVC-family/DCVC-RT/src/layers/extensions/inference/impl.cpp diff --git a/src/layers/extensions/inference/kernel.cu b/DCVC-family/DCVC-RT/src/layers/extensions/inference/kernel.cu similarity index 100% rename from src/layers/extensions/inference/kernel.cu rename to DCVC-family/DCVC-RT/src/layers/extensions/inference/kernel.cu diff --git a/DCVC-family/DCVC-RT/src/layers/extensions/inference/setup.py b/DCVC-family/DCVC-RT/src/layers/extensions/inference/setup.py new file mode 100644 index 0000000..6a25fd5 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/layers/extensions/inference/setup.py @@ -0,0 +1,32 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import os +import glob +import sys +from setuptools import setup +from torch.utils.cpp_extension import BuildExtension, CUDAExtension + + +cxx_flags = ["-O3"] +nvcc_flags = ["-O3", "--use_fast_math", "--extra-device-vectorization", "-arch=native"] +if sys.platform == 'win32': + cxx_flags = ["/O2"] + + +setup( + name='inference_extensions_cuda', + ext_modules=[ + CUDAExtension( + name='inference_extensions_cuda', + sources=glob.glob('*.cpp') + glob.glob('*.cu'), + extra_compile_args={ + "cxx": cxx_flags, + "nvcc": nvcc_flags, + }, + ), + ], + cmdclass={ + 'build_ext': BuildExtension + } +) diff --git a/DCVC-family/DCVC-RT/src/layers/layers.py b/DCVC-family/DCVC-RT/src/layers/layers.py new file mode 100644 index 0000000..a51e93d --- /dev/null +++ b/DCVC-family/DCVC-RT/src/layers/layers.py @@ -0,0 +1,156 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import torch +from torch import nn +from .cuda_inference import CUSTOMIZED_CUDA_INFERENCE +if CUSTOMIZED_CUDA_INFERENCE: + from .cuda_inference import DepthConvProxy, SubpelConv2xProxy + + +class WSiLU(nn.Module): + def __init__(self): + super().__init__() + + def forward(self, x): + return torch.sigmoid(4.0 * x) * x + + +class WSiLUChunkAdd(nn.Module): + def __init__(self): + super().__init__() + self.silu = WSiLU() + + def forward(self, x): + x1, x2 = self.silu(x).chunk(2, 1) + return x1 + x2 + + +class SubpelConv2x(nn.Module): + def __init__(self, in_ch, out_ch, kernel_size, padding=0): + super().__init__() + self.conv = nn.Sequential( + nn.Conv2d(in_ch, out_ch * 4, kernel_size=kernel_size, padding=padding), + nn.PixelShuffle(2), + ) + self.padding = padding + + self.proxy = None + + def forward(self, x, to_cat=None, cat_at_front=True): + if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: + return self.forward_torch(x, to_cat, cat_at_front) + + return self.forward_cuda(x, to_cat, cat_at_front) + + def forward_torch(self, x, to_cat=None, cat_at_front=True): + out = self.conv(x) + if to_cat is None: + return out + if cat_at_front: + return torch.cat((to_cat, out), dim=1) + return torch.cat((out, to_cat), dim=1) + + def forward_cuda(self, x, to_cat=None, cat_at_front=True): + if self.proxy is None: + self.proxy = SubpelConv2xProxy() + self.proxy.set_param(self.conv[0].weight, self.conv[0].bias, self.padding) + + if to_cat is None: + return self.proxy.forward(x) + + return self.proxy.forward_with_cat(x, to_cat, cat_at_front) + + +class DepthConvBlock(nn.Module): + def __init__(self, in_ch, out_ch, shortcut=False, force_adaptor=False): + super().__init__() + self.adaptor = None + if in_ch != out_ch or force_adaptor: + self.adaptor = nn.Conv2d(in_ch, out_ch, 1) + self.shortcut = shortcut + self.dc = nn.Sequential( + nn.Conv2d(out_ch, out_ch, 1), + WSiLU(), + nn.Conv2d(out_ch, out_ch, 3, padding=1, groups=out_ch), + nn.Conv2d(out_ch, out_ch, 1), + ) + self.ffn = nn.Sequential( + nn.Conv2d(out_ch, out_ch * 4, 1), + WSiLUChunkAdd(), + nn.Conv2d(out_ch * 2, out_ch, 1), + ) + + self.proxy = None + + def forward(self, x, quant_step=None, to_cat=None, cat_at_front=True): + if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: + return self.forward_torch(x, quant_step, to_cat, cat_at_front) + + return self.forward_cuda(x, quant_step, to_cat, cat_at_front) + + def forward_torch(self, x, quant_step=None, to_cat=None, cat_at_front=True): + if self.adaptor is not None: + x = self.adaptor(x) + out = self.dc(x) + x + out = self.ffn(out) + out + if self.shortcut: + out = out + x + if quant_step is not None: + out = out * quant_step + if to_cat is not None: + if cat_at_front: + out = torch.cat((to_cat, out), dim=1) + else: + out = torch.cat((out, to_cat), dim=1) + return out + + def forward_cuda(self, x, quant_step=None, to_cat=None, cat_at_front=True): + if self.proxy is None: + self.proxy = DepthConvProxy() + if self.adaptor is not None: + self.proxy.set_param_with_adaptor(self.dc[0].weight, self.dc[0].bias, + self.dc[2].weight, self.dc[2].bias, + self.dc[3].weight, self.dc[3].bias, + self.ffn[0].weight, self.ffn[0].bias, + self.ffn[2].weight, self.ffn[2].bias, + self.adaptor.weight, self.adaptor.bias, + self.shortcut) + else: + self.proxy.set_param(self.dc[0].weight, self.dc[0].bias, + self.dc[2].weight, self.dc[2].bias, + self.dc[3].weight, self.dc[3].bias, + self.ffn[0].weight, self.ffn[0].bias, + self.ffn[2].weight, self.ffn[2].bias, + self.shortcut) + + if quant_step is not None: + return self.proxy.forward_with_quant_step(x, quant_step) + if to_cat is not None: + return self.proxy.forward_with_cat(x, to_cat, cat_at_front) + + return self.proxy.forward(x) + + +class ResidualBlockWithStride2(nn.Module): + def __init__(self, in_ch, out_ch): + super().__init__() + self.down = nn.Conv2d(in_ch, out_ch, 2, stride=2) + self.conv = DepthConvBlock(out_ch, out_ch, shortcut=True) + + def forward(self, x): + x = self.down(x) + out = self.conv(x) + return out + + +class ResidualBlockUpsample(nn.Module): + def __init__(self, in_ch, out_ch): + super().__init__() + self.up = SubpelConv2x(in_ch, out_ch, 1) + self.conv = DepthConvBlock(out_ch, out_ch, shortcut=True) + + def forward(self, x): + out = self.up(x) + out = self.conv(out) + return out diff --git a/DCVC-family/DCVC-RT/src/models/common_model.py b/DCVC-family/DCVC-RT/src/models/common_model.py new file mode 100644 index 0000000..dc18b65 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/models/common_model.py @@ -0,0 +1,296 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import torch +from torch import nn + +from ..layers.cuda_inference import combine_for_reading_2x, \ + restore_y_2x, restore_y_2x_with_cat_after, add_and_multiply, \ + replicate_pad, restore_y_4x, clamp_reciprocal_with_quant +from .entropy_models import BitEstimator, GaussianEncoder, EntropyCoder + + +class CompressionModel(nn.Module): + def __init__(self, z_channel, extra_qp=0): + super().__init__() + + self.z_channel = z_channel + self.entropy_coder = None + self.bit_estimator_z = BitEstimator(64 + extra_qp, z_channel) + self.gaussian_encoder = GaussianEncoder() + + self.masks = {} + self.cuda_streams = {} + + def get_cuda_stream(self, device, idx=0, priority=0): + key = f"{device}_{priority}_{idx}" + if key not in self.cuda_streams: + self.cuda_streams[key] = torch.cuda.Stream(device, priority=priority) + return self.cuda_streams[key] + + @staticmethod + def get_qp_num(): + return 64 + + @staticmethod + def get_padding_size(height, width, p=64): + new_h = (height + p - 1) // p * p + new_w = (width + p - 1) // p * p + padding_right = new_w - width + padding_bottom = new_h - height + return padding_right, padding_bottom + + @staticmethod + def get_downsampled_shape(height, width, p): + new_h = (height + p - 1) // p * p + new_w = (width + p - 1) // p * p + return int(new_h / p + 0.5), int(new_w / p + 0.5) + + def update(self, force_zero_thres=None): + self.entropy_coder = EntropyCoder() + self.gaussian_encoder.update(self.entropy_coder, force_zero_thres=force_zero_thres) + self.bit_estimator_z.update(self.entropy_coder) + + def set_use_two_entropy_coders(self, use_two_entropy_coders): + self.entropy_coder.set_use_two_entropy_coders(use_two_entropy_coders) + + def pad_for_y(self, y): + _, _, H, W = y.size() + padding_r, padding_b = self.get_padding_size(H, W, 4) + y_pad = replicate_pad(y, padding_b, padding_r) + return y_pad + + def separate_prior(self, params, is_video=False): + if is_video: + quant_step, scales, means = params.chunk(3, 1) + quant_step = torch.clamp_min(quant_step, 0.5) + q_enc = 1. / quant_step + q_dec = quant_step + else: + q = params[:, :2, :, :] + q_enc, q_dec = (torch.sigmoid(q) * 1.5 + 0.5).chunk(2, 1) + scales, means = params[:, 2:, :, :].chunk(2, 1) + return q_enc, q_dec, scales, means + + @staticmethod + def separate_prior_for_video_encoding(params, y): + q_dec, scales, means = params.chunk(3, 1) + q_dec, y = clamp_reciprocal_with_quant(q_dec, y, 0.5) + return y, q_dec, scales, means + + @staticmethod + def separate_prior_for_video_decoding(params): + quant_step, scales, means = params.chunk(3, 1) + quant_step = torch.clamp_min(quant_step, 0.5) + return quant_step, scales, means + + def process_with_mask(self, y, scales, means, mask): + return self.gaussian_encoder.process_with_mask(y, scales, means, mask) + + @staticmethod + def get_one_mask(micro_mask, height, width, dtype, device): + mask = torch.tensor(micro_mask, dtype=dtype, device=device) + mask = mask.repeat((height + 1) // 2, (width + 1) // 2) + mask = mask[:height, :width] + mask = torch.unsqueeze(mask, 0) + mask = torch.unsqueeze(mask, 0) + return mask + + def get_mask_4x(self, batch, channel, height, width, dtype, device): + curr_mask_str = f"{batch}_{channel}_{width}_{height}_4x" + with torch.no_grad(): + if curr_mask_str not in self.masks: + assert channel % 4 == 0 + m = torch.ones((batch, channel // 4, height, width), dtype=dtype, device=device) + m0 = self.get_one_mask(((1, 0), (0, 0)), height, width, dtype, device) + m1 = self.get_one_mask(((0, 1), (0, 0)), height, width, dtype, device) + m2 = self.get_one_mask(((0, 0), (1, 0)), height, width, dtype, device) + m3 = self.get_one_mask(((0, 0), (0, 1)), height, width, dtype, device) + + mask_0 = torch.cat((m * m0, m * m1, m * m2, m * m3), dim=1) + mask_1 = torch.cat((m * m3, m * m2, m * m1, m * m0), dim=1) + mask_2 = torch.cat((m * m2, m * m3, m * m0, m * m1), dim=1) + mask_3 = torch.cat((m * m1, m * m0, m * m3, m * m2), dim=1) + + self.masks[curr_mask_str] = [mask_0, mask_1, mask_2, mask_3] + return self.masks[curr_mask_str] + + def get_mask_2x(self, batch, channel, height, width, dtype, device): + curr_mask_str = f"{batch}_{channel}_{width}_{height}_2x" + with torch.no_grad(): + if curr_mask_str not in self.masks: + assert channel % 2 == 0 + m = torch.ones((batch, channel // 2, height, width), dtype=dtype, device=device) + m0 = self.get_one_mask(((1, 0), (0, 1)), height, width, dtype, device) + m1 = self.get_one_mask(((0, 1), (1, 0)), height, width, dtype, device) + + mask_0 = torch.cat((m * m0, m * m1), dim=1) + mask_1 = torch.cat((m * m1, m * m0), dim=1) + + self.masks[curr_mask_str] = [mask_0, mask_1] + return self.masks[curr_mask_str] + + @staticmethod + def single_part_for_writing_4x(x): + x0, x1, x2, x3 = x.chunk(4, 1) + return (x0 + x1) + (x2 + x3) + + @staticmethod + def single_part_for_writing_2x(x): + x0, x1 = x.chunk(2, 1) + return x0 + x1 + + def compress_prior_2x(self, y, common_params, y_spatial_prior): + y, q_dec, scales, means = self.separate_prior_for_video_encoding(common_params, y) + dtype = y.dtype + device = y.device + B, C, H, W = y.size() + mask_0, mask_1 = self.get_mask_2x(B, C, H, W, dtype, device) + + _, y_q_0, y_hat_0, s_hat_0 = self.process_with_mask(y, scales, means, mask_0) + cat_params = torch.cat((y_hat_0, common_params), dim=1) + scales, means = y_spatial_prior(cat_params).chunk(2, 1) + _, y_q_1, y_hat_1, s_hat_1 = self.process_with_mask(y, scales, means, mask_1) + + y_hat = add_and_multiply(y_hat_0, y_hat_1, q_dec) + + y_q_w_0 = self.single_part_for_writing_2x(y_q_0) + y_q_w_1 = self.single_part_for_writing_2x(y_q_1) + s_w_0 = self.single_part_for_writing_2x(s_hat_0) + s_w_1 = self.single_part_for_writing_2x(s_hat_1) + return y_q_w_0, y_q_w_1, s_w_0, s_w_1, y_hat + + def decompress_prior_2x(self, common_params, y_spatial_prior): + infos = self.decompress_prior_2x_part1(common_params) + y_hat = self.decompress_prior_2x_part2(common_params, y_spatial_prior, infos) + return y_hat + + def decompress_prior_2x_part1(self, common_params): + q_dec, scales, means = self.separate_prior_for_video_decoding(common_params) + dtype = means.dtype + device = means.device + B, C, H, W = means.size() + mask_0, mask_1 = self.get_mask_2x(B, C, H, W, dtype, device) + + scales_r = combine_for_reading_2x(scales, mask_0, inplace=False) + indexes, skip_cond = self.gaussian_encoder.build_indexes_decoder(scales_r) + self.gaussian_encoder.decode_y(indexes) + infos = { + "q_dec": q_dec, + "mask_0": mask_0, + "mask_1": mask_1, + "means": means, + "scales_r": scales_r, + "skip_cond": skip_cond, + "indexes": indexes, + } + return infos + + def decompress_prior_2x_part2(self, common_params, y_spatial_prior, infos): + dtype = common_params.dtype + device = common_params.device + y_q_r = self.gaussian_encoder.get_y(infos["scales_r"].shape, + infos["scales_r"].numel(), + dtype, device, + infos["skip_cond"], infos["indexes"]) + y_hat_0, cat_params = restore_y_2x_with_cat_after(y_q_r, infos["means"], infos["mask_0"], + common_params) + scales, means = y_spatial_prior(cat_params).chunk(2, 1) + scales_r = combine_for_reading_2x(scales, infos["mask_1"], inplace=True) + y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) + y_hat_1 = restore_y_2x(y_q_r, means, infos["mask_1"]) + + y_hat = add_and_multiply(y_hat_0, y_hat_1, infos["q_dec"]) + return y_hat + + def compress_prior_4x(self, y, common_params, y_spatial_prior_reduction, + y_spatial_prior_adaptor_1, y_spatial_prior_adaptor_2, + y_spatial_prior_adaptor_3, y_spatial_prior): + ''' + y_0 means split in channel, the 0/4 quater + y_1 means split in channel, the 1/4 quater + y_2 means split in channel, the 2/4 quater + y_3 means split in channel, the 3/4 quater + y_?_0, means multiply with mask_0 + y_?_1, means multiply with mask_1 + y_?_2, means multiply with mask_2 + y_?_3, means multiply with mask_3 + ''' + q_enc, q_dec, scales, means = self.separate_prior(common_params, False) + common_params = y_spatial_prior_reduction(common_params) + dtype = y.dtype + device = y.device + B, C, H, W = y.size() + mask_0, mask_1, mask_2, mask_3 = self.get_mask_4x(B, C, H, W, dtype, device) + + y = y * q_enc + + _, y_q_0, y_hat_0, s_hat_0 = self.process_with_mask(y, scales, means, mask_0) + + y_hat_so_far = y_hat_0 + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_1(params)).chunk(2, 1) + _, y_q_1, y_hat_1, s_hat_1 = self.process_with_mask(y, scales, means, mask_1) + + y_hat_so_far = y_hat_so_far + y_hat_1 + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_2(params)).chunk(2, 1) + _, y_q_2, y_hat_2, s_hat_2 = self.process_with_mask(y, scales, means, mask_2) + + y_hat_so_far = y_hat_so_far + y_hat_2 + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_3(params)).chunk(2, 1) + _, y_q_3, y_hat_3, s_hat_3 = self.process_with_mask(y, scales, means, mask_3) + + y_hat = y_hat_so_far + y_hat_3 + y_hat = y_hat * q_dec + + y_q_w_0 = self.single_part_for_writing_4x(y_q_0) + y_q_w_1 = self.single_part_for_writing_4x(y_q_1) + y_q_w_2 = self.single_part_for_writing_4x(y_q_2) + y_q_w_3 = self.single_part_for_writing_4x(y_q_3) + s_w_0 = self.single_part_for_writing_4x(s_hat_0) + s_w_1 = self.single_part_for_writing_4x(s_hat_1) + s_w_2 = self.single_part_for_writing_4x(s_hat_2) + s_w_3 = self.single_part_for_writing_4x(s_hat_3) + return y_q_w_0, y_q_w_1, y_q_w_2, y_q_w_3, s_w_0, s_w_1, s_w_2, s_w_3, y_hat + + def decompress_prior_4x(self, common_params, y_spatial_prior_reduction, + y_spatial_prior_adaptor_1, y_spatial_prior_adaptor_2, + y_spatial_prior_adaptor_3, y_spatial_prior): + _, quant_step, scales, means = self.separate_prior(common_params, False) + common_params = y_spatial_prior_reduction(common_params) + dtype = means.dtype + device = means.device + B, C, H, W = means.size() + mask_0, mask_1, mask_2, mask_3 = self.get_mask_4x(B, C, H, W, dtype, device) + + scales_r = self.single_part_for_writing_4x(scales * mask_0) + y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) + y_hat_curr_step = restore_y_4x(y_q_r, means, mask_0) + y_hat_so_far = y_hat_curr_step + + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_1(params)).chunk(2, 1) + scales_r = self.single_part_for_writing_4x(scales * mask_1) + y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) + y_hat_curr_step = restore_y_4x(y_q_r, means, mask_1) + y_hat_so_far = y_hat_so_far + y_hat_curr_step + + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_2(params)).chunk(2, 1) + scales_r = self.single_part_for_writing_4x(scales * mask_2) + y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) + y_hat_curr_step = restore_y_4x(y_q_r, means, mask_2) + y_hat_so_far = y_hat_so_far + y_hat_curr_step + + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_3(params)).chunk(2, 1) + scales_r = self.single_part_for_writing_4x(scales * mask_3) + y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) + y_hat_curr_step = restore_y_4x(y_q_r, means, mask_3) + y_hat_so_far = y_hat_so_far + y_hat_curr_step + + y_hat = y_hat_so_far * quant_step + + return y_hat diff --git a/DCVC-family/DCVC-RT/src/models/entropy_models.py b/DCVC-family/DCVC-RT/src/models/entropy_models.py new file mode 100644 index 0000000..9b64d28 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/models/entropy_models.py @@ -0,0 +1,341 @@ +import math + +import torch +import numpy as np +from torch import nn +import torch.nn.functional as F + +from ..layers.cuda_inference import build_index_dec, build_index_enc, process_with_mask + + +class EntropyCoder(): + def __init__(self): + super().__init__() + + from MLCodec_extensions_cpp import RansEncoder, RansDecoder + self.encoder = RansEncoder() + self.decoder = RansDecoder() + + @staticmethod + def pmf_to_quantized_cdf(pmf, precision=16): + from MLCodec_extensions_cpp import pmf_to_quantized_cdf as _pmf_to_cdf + cdf = _pmf_to_cdf(pmf.tolist(), precision) + cdf = torch.IntTensor(cdf) + return cdf + + @staticmethod + def pmf_to_cdf(pmf, tail_mass, pmf_length, max_length): + entropy_coder_precision = 16 + cdf = torch.zeros((len(pmf_length), max_length + 2), dtype=torch.int32) + for i, p in enumerate(pmf): + prob = torch.cat((p[: pmf_length[i]], tail_mass[i]), dim=0) + _cdf = EntropyCoder.pmf_to_quantized_cdf(prob, entropy_coder_precision) + cdf[i, : _cdf.size(0)] = _cdf + return cdf + + def reset(self): + self.encoder.reset() + + def add_cdf(self, cdf, cdf_length, offset): + enc_cdf_idx = self.encoder.add_cdf(cdf, cdf_length, offset) + dec_cdf_idx = self.decoder.add_cdf(cdf, cdf_length, offset) + assert enc_cdf_idx == dec_cdf_idx + return enc_cdf_idx + + def encode_y(self, symbols, cdf_group_index): + # symbols: int16, high 8 bits: int8 symbol to be encoded; low 8 bits: uint8 index to use + assert symbols.dtype == torch.int16 + self.encoder.encode_y(symbols.cpu().numpy(), cdf_group_index) + + def encode_z(self, symbols, cdf_group_index, start_offset, per_channel_size): + self.encoder.encode_z(symbols.to(torch.int8).cpu().numpy(), + cdf_group_index, start_offset, per_channel_size) + + def flush(self): + self.encoder.flush() + + def get_encoded_stream(self): + return self.encoder.get_encoded_stream().tobytes() + + def set_stream(self, stream): + self.decoder.set_stream((np.frombuffer(stream, dtype=np.uint8))) + + def decode_y(self, indexes, cdf_group_index): + self.decoder.decode_y(indexes.to(torch.uint8).cpu().numpy(), cdf_group_index) + + def decode_and_get_y(self, indexes, cdf_group_index, device, dtype): + rv = self.decoder.decode_and_get_y(indexes.to(torch.uint8).cpu().numpy(), cdf_group_index) + rv = torch.as_tensor(rv) + return rv.to(device).to(dtype) + + def decode_z(self, total_size, cdf_group_index, start_offset, per_channel_size): + self.decoder.decode_z(total_size, cdf_group_index, start_offset, per_channel_size) + + def get_decoded_tensor(self, device, dtype, non_blocking=False): + rv = self.decoder.get_decoded_tensor() + rv = torch.as_tensor(rv) + return rv.to(device, non_blocking=non_blocking).to(dtype) + + def set_use_two_entropy_coders(self, use_two_entropy_coders): + self.encoder.set_use_two_encoders(use_two_entropy_coders) + self.decoder.set_use_two_decoders(use_two_entropy_coders) + + +class Bitparm(nn.Module): + def __init__(self, qp_num, channel, final=False): + super().__init__() + self.final = final + self.h = nn.Parameter(torch.nn.init.normal_( + torch.empty([qp_num, channel, 1, 1]), 0, 0.01)) + self.b = nn.Parameter(torch.nn.init.normal_( + torch.empty([qp_num, channel, 1, 1]), 0, 0.01)) + if not final: + self.a = nn.Parameter(torch.nn.init.normal_( + torch.empty([qp_num, channel, 1, 1]), 0, 0.01)) + else: + self.a = None + + def forward(self, x, index): + h = torch.index_select(self.h, 0, index) + b = torch.index_select(self.b, 0, index) + x = x * F.softplus(h) + b + if self.final: + return x + + a = torch.index_select(self.a, 0, index) + return x + torch.tanh(x) * torch.tanh(a) + + +class AEHelper(): + def __init__(self): + super().__init__() + self.entropy_coder = None + self.cdf_group_index = None + self._offset = None + self._quantized_cdf = None + self._cdf_length = None + + def set_cdf_info(self, quantized_cdf, cdf_length, offset): + self._quantized_cdf = quantized_cdf.cpu().numpy() + self._cdf_length = cdf_length.reshape(-1).int().cpu().numpy() + self._offset = offset.reshape(-1).int().cpu().numpy() + + def get_cdf_info(self): + return self._quantized_cdf, \ + self._cdf_length, \ + self._offset + + +class BitEstimator(AEHelper, nn.Module): + def __init__(self, qp_num, channel): + super().__init__() + self.f1 = Bitparm(qp_num, channel) + self.f2 = Bitparm(qp_num, channel) + self.f3 = Bitparm(qp_num, channel) + self.f4 = Bitparm(qp_num, channel, True) + self.qp_num = qp_num + self.channel = channel + + def forward(self, x, index): + return self.get_cdf(x, index) + + def get_logits_cdf(self, x, index): + x = self.f1(x, index) + x = self.f2(x, index) + x = self.f3(x, index) + x = self.f4(x, index) + return x + + def get_cdf(self, x, index): + return torch.sigmoid(self.get_logits_cdf(x, index)) + + def update(self, entropy_coder): + self.entropy_coder = entropy_coder + + with torch.no_grad(): + device = next(self.parameters()).device + medians = torch.zeros((self.qp_num, self.channel, 1, 1), device=device) + index = torch.arange(self.qp_num, device=device, dtype=torch.int32) + + minima = medians + 8 + for i in range(8, 1, -1): + samples = torch.zeros_like(medians) - i + probs = self.forward(samples, index) + minima = torch.where(probs < torch.zeros_like(medians) + 0.0001, + torch.zeros_like(medians) + i, minima) + + maxima = medians + 8 + for i in range(8, 1, -1): + samples = torch.zeros_like(medians) + i + probs = self.forward(samples, index) + maxima = torch.where(probs > torch.zeros_like(medians) + 0.9999, + torch.zeros_like(medians) + i, maxima) + + minima = minima.int() + maxima = maxima.int() + + offset = -minima + + pmf_start = medians - minima + pmf_length = maxima + minima + 1 + + max_length = pmf_length.max() + device = pmf_start.device + samples = torch.arange(max_length, device=device) + + samples = samples[None, None, None, :] + pmf_start + + half = float(0.5) + + lower = self.forward(samples - half, index) + upper = self.forward(samples + half, index) + pmf = upper - lower + + pmf = pmf[:, :, 0, :] + upper = self.forward(maxima.to(torch.float32), index) + tail_mass = lower[:, :, 0, :1] + (1.0 - upper[:, :, 0, -1:]) + + pmf = pmf.reshape([-1, max_length]) + tail_mass = tail_mass.reshape([-1, 1]) + pmf_length = pmf_length.reshape([-1]) + offset = offset.reshape([-1]) + quantized_cdf = EntropyCoder.pmf_to_cdf(pmf, tail_mass, pmf_length, max_length) + cdf_length = pmf_length + 2 + self.set_cdf_info(quantized_cdf, cdf_length, offset) + self.cdf_group_index = self.entropy_coder.add_cdf(*self.get_cdf_info()) + + def build_indexes(self, size, qp): + B, C, H, W = size + indexes = torch.arange(C, dtype=torch.int).view(1, -1, 1, 1) + qp * self.channel + return indexes.repeat(B, 1, H, W) + + def encode_z(self, x, qp): + _, _, H, W = x.size() + return self.entropy_coder.encode_z(x.reshape(-1), self.cdf_group_index, qp * self.channel, + H * W) + + def decode_z(self, size, qp): + self.entropy_coder.decode_z(self.channel * size[0] * size[1], self.cdf_group_index, + qp * self.channel, size[0] * size[1]) + + def get_z(self, size, device, dtype): + output_size = (1, self.channel, size[0], size[1]) + val = self.entropy_coder.get_decoded_tensor(device, dtype, non_blocking=True) + return val.reshape(output_size) + + +class GaussianEncoder(AEHelper): + def __init__(self): + super().__init__() + self.scale_min = 0.11 + self.scale_max = 16.0 + self.scale_level = 128 # <= 256 + self.scale_table = self.get_scale_table(self.scale_min, self.scale_max, self.scale_level) + + self.log_scale_min = math.log(self.scale_min) + self.log_scale_max = math.log(self.scale_max) + self.log_scale_step = (self.log_scale_max - self.log_scale_min) / (self.scale_level - 1) + self.log_step_recip = 1. / self.log_scale_step + + self.force_zero_thres = None + self.decode_index_cache = {} + self.decode_zeros_cache = {} + + @staticmethod + def get_scale_table(min_val, max_val, levels): + return torch.exp(torch.linspace(math.log(min_val), math.log(max_val), levels)) + + def update(self, entropy_coder, force_zero_thres=None): + self.entropy_coder = entropy_coder + self.force_zero_thres = force_zero_thres + + pmf_center = torch.zeros_like(self.scale_table) + 8 + scales = torch.zeros_like(pmf_center) + self.scale_table + cdf_distribution = torch.distributions.normal.Normal(0., scales) + for i in range(8, 1, -1): + samples = torch.zeros_like(pmf_center) + i + probs = cdf_distribution.cdf(samples) + probs = torch.squeeze(probs) + pmf_center = torch.where(probs > torch.zeros_like(pmf_center) + 0.9999, + torch.zeros_like(pmf_center) + i, pmf_center) + + pmf_center = pmf_center.int() + pmf_length = 2 * pmf_center + 1 + max_length = torch.max(pmf_length).item() + + device = pmf_center.device + samples = torch.arange(max_length, device=device) - pmf_center[:, None] + samples = samples.float() + + scales = torch.zeros_like(samples) + self.scale_table[:, None] + cdf_distribution = torch.distributions.normal.Normal(0., scales) + + upper = cdf_distribution.cdf(samples + 0.5) + lower = cdf_distribution.cdf(samples - 0.5) + pmf = upper - lower + + tail_mass = 2 * lower[:, :1] + + quantized_cdf = torch.Tensor(len(pmf_length), max_length + 2) + quantized_cdf = EntropyCoder.pmf_to_cdf(pmf, tail_mass, pmf_length, max_length) + + self.set_cdf_info(quantized_cdf, pmf_length+2, -pmf_center) + self.cdf_group_index = self.entropy_coder.add_cdf(*self.get_cdf_info()) + + def process_with_mask(self, y, scales, means, mask): + return process_with_mask(y, scales, means, mask, self.force_zero_thres) + + def build_indexes_decoder(self, scales): + scales = scales.reshape(-1) + indexes, skip_cond = build_index_dec(scales, self.scale_min, self.scale_max, + self.log_scale_min, self.log_step_recip, + self.force_zero_thres) + if self.force_zero_thres is not None: + indexes = indexes[skip_cond] + return indexes, skip_cond + + def build_indexes_encoder(self, symbols, scales): + symbols = symbols.reshape(-1) + scales = scales.reshape(-1) + symbols = build_index_enc(symbols, scales, self.scale_min, self.scale_max, + self.log_scale_min, self.log_step_recip, self.force_zero_thres) + return symbols + + def encode_y(self, x, scales): + symbols = self.build_indexes_encoder(x, scales) + return self.entropy_coder.encode_y(symbols, self.cdf_group_index) + + def get_decode_index_cache(self, num, device): + if num not in self.decode_index_cache: + c = torch.arange(0, num, dtype=torch.int32, device=device) + self.decode_index_cache[num] = c + + return self.decode_index_cache[num] + + def get_decode_zeros_cache(self, num, device): + if num not in self.decode_zeros_cache: + c = torch.zeros(num, dtype=torch.int32, device=device) + self.decode_zeros_cache[num] = c + + return self.decode_zeros_cache[num].clone() + + def decode_and_get_y(self, scales, dtype, device): + indexes, skip_cond = self.build_indexes_decoder(scales) + self.decode_y(indexes) + return self.get_y(scales.shape, scales.numel(), dtype, device, skip_cond, indexes) + + def decode_y(self, indexes): + self.entropy_coder.decode_y(indexes, self.cdf_group_index) + + def get_y(self, shape, numel, dtype, device, skip_cond, indexes): + if len(indexes) == 0: + return torch.zeros(shape, dtype=dtype, device=device) + if skip_cond is not None: + curr_index = self.get_decode_index_cache(numel, device) + back_index = self.get_decode_zeros_cache(numel, device) + back_index.masked_scatter_(skip_cond, curr_index) + val = self.entropy_coder.get_decoded_tensor(device, dtype, non_blocking=True) + if skip_cond is not None: + y = torch.index_select(val, 0, back_index) * skip_cond + return y.reshape(shape) + return val.reshape(shape) diff --git a/DCVC-family/DCVC-RT/src/models/image_model.py b/DCVC-family/DCVC-RT/src/models/image_model.py new file mode 100644 index 0000000..fa1ea67 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/models/image_model.py @@ -0,0 +1,209 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import torch +from torch import nn +import torch.nn.functional as F + + +from .common_model import CompressionModel +from ..layers.layers import DepthConvBlock, ResidualBlockUpsample, ResidualBlockWithStride2 +from ..layers.cuda_inference import CUSTOMIZED_CUDA_INFERENCE, round_and_to_int8 + +g_ch_src = 3 * 8 * 8 +g_ch_enc_dec = 368 + + +class IntraEncoder(nn.Module): + def __init__(self, N): + super().__init__() + + self.enc_1 = DepthConvBlock(g_ch_src, g_ch_enc_dec) + self.enc_2 = nn.Sequential( + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + nn.Conv2d(g_ch_enc_dec, N, 3, stride=2, padding=1), + ) + + def forward(self, x, quant_step): + out = F.pixel_unshuffle(x, 8) + if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: + return self.forward_torch(out, quant_step) + + return self.forward_cuda(out, quant_step) + + def forward_torch(self, out, quant_step): + out = self.enc_1(out) + out = out * quant_step + return self.enc_2(out) + + def forward_cuda(self, out, quant_step): + out = self.enc_1(out, quant_step=quant_step) + return self.enc_2(out) + + +class IntraDecoder(nn.Module): + def __init__(self, N): + super().__init__() + + self.dec_1 = nn.Sequential( + ResidualBlockUpsample(N, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + ) + self.dec_2 = DepthConvBlock(g_ch_enc_dec, g_ch_src) + + def forward(self, x, quant_step): + if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: + return self.forward_torch(x, quant_step) + + return self.forward_cuda(x, quant_step) + + def forward_torch(self, x, quant_step): + out = self.dec_1(x) + out = out * quant_step + out = self.dec_2(out) + out = F.pixel_shuffle(out, 8) + return out + + def forward_cuda(self, x, quant_step): + out = self.dec_1[0](x) + out = self.dec_1[1](out) + out = self.dec_1[2](out) + out = self.dec_1[3](out) + out = self.dec_1[4](out) + out = self.dec_1[5](out) + out = self.dec_1[6](out) + out = self.dec_1[7](out) + out = self.dec_1[8](out) + out = self.dec_1[9](out) + out = self.dec_1[10](out) + out = self.dec_1[11](out) + out = self.dec_1[12](out, quant_step=quant_step) + out = self.dec_2(out) + out = F.pixel_shuffle(out, 8) + return out + + +class DMCI(CompressionModel): + def __init__(self, N=256, z_channel=128): + super().__init__(z_channel=z_channel) + + self.enc = IntraEncoder(N) + + self.hyper_enc = nn.Sequential( + DepthConvBlock(N, z_channel), + ResidualBlockWithStride2(z_channel, z_channel), + ResidualBlockWithStride2(z_channel, z_channel), + ) + + self.hyper_dec = nn.Sequential( + ResidualBlockUpsample(z_channel, z_channel), + ResidualBlockUpsample(z_channel, z_channel), + DepthConvBlock(z_channel, N), + ) + + self.y_prior_fusion = nn.Sequential( + DepthConvBlock(N, N * 2), + DepthConvBlock(N * 2, N * 2), + DepthConvBlock(N * 2, N * 2), + nn.Conv2d(N * 2, N * 2 + 2, 1), + ) + + self.y_spatial_prior_reduction = nn.Conv2d(N * 2 + 2, N * 1, 1) + self.y_spatial_prior_adaptor_1 = DepthConvBlock(N * 2, N * 2, force_adaptor=True) + self.y_spatial_prior_adaptor_2 = DepthConvBlock(N * 2, N * 2, force_adaptor=True) + self.y_spatial_prior_adaptor_3 = DepthConvBlock(N * 2, N * 2, force_adaptor=True) + self.y_spatial_prior = nn.Sequential( + DepthConvBlock(N * 2, N * 2), + DepthConvBlock(N * 2, N * 2), + DepthConvBlock(N * 2, N * 2), + nn.Conv2d(N * 2, N * 2, 1), + ) + + self.dec = IntraDecoder(N) + + self.q_scale_enc = nn.Parameter(torch.ones((self.get_qp_num(), g_ch_enc_dec, 1, 1))) + self.q_scale_dec = nn.Parameter(torch.ones((self.get_qp_num(), g_ch_enc_dec, 1, 1))) + + def compress(self, x, qp): + device = x.device + curr_q_enc = self.q_scale_enc[qp:qp+1, :, :, :] + curr_q_dec = self.q_scale_dec[qp:qp+1, :, :, :] + + y = self.enc(x, curr_q_enc) + y_pad = self.pad_for_y(y) + z = self.hyper_enc(y_pad) + z_hat, z_hat_write = round_and_to_int8(z) + + params = self.hyper_dec(z_hat) + params = self.y_prior_fusion(params) + _, _, yH, yW = y.shape + params = params[:, :, :yH, :yW].contiguous() + y_q_w_0, y_q_w_1, y_q_w_2, y_q_w_3, s_w_0, s_w_1, s_w_2, s_w_3, y_hat = \ + self.compress_prior_4x( + y, params, self.y_spatial_prior_reduction, + self.y_spatial_prior_adaptor_1, self.y_spatial_prior_adaptor_2, + self.y_spatial_prior_adaptor_3, self.y_spatial_prior) + + cuda_event = torch.cuda.Event() + cuda_event.record() + x_hat = self.dec(y_hat, curr_q_dec).clamp_(0, 1) + + cuda_stream = self.get_cuda_stream(device=device, priority=-1) + with torch.cuda.stream(cuda_stream): + cuda_event.wait() + self.entropy_coder.reset() + self.bit_estimator_z.encode_z(z_hat_write, qp) + self.gaussian_encoder.encode_y(y_q_w_0, s_w_0) + self.gaussian_encoder.encode_y(y_q_w_1, s_w_1) + self.gaussian_encoder.encode_y(y_q_w_2, s_w_2) + self.gaussian_encoder.encode_y(y_q_w_3, s_w_3) + self.entropy_coder.flush() + + bit_stream = self.entropy_coder.get_encoded_stream() + + torch.cuda.synchronize(device=device) + result = { + "bit_stream": bit_stream, + "x_hat": x_hat, + } + return result + + def decompress(self, bit_stream, sps, qp): + dtype = next(self.parameters()).dtype + device = next(self.parameters()).device + curr_q_dec = self.q_scale_dec[qp:qp+1, :, :, :] + + self.entropy_coder.set_use_two_entropy_coders(sps['ec_part'] == 1) + self.entropy_coder.set_stream(bit_stream) + z_size = self.get_downsampled_shape(sps['height'], sps['width'], 64) + y_height, y_width = self.get_downsampled_shape(sps['height'], sps['width'], 16) + self.bit_estimator_z.decode_z(z_size, qp) + z_q = self.bit_estimator_z.get_z(z_size, device, dtype) + z_hat = z_q + + params = self.hyper_dec(z_hat) + params = self.y_prior_fusion(params) + params = params[:, :, :y_height, :y_width].contiguous() + y_hat = self.decompress_prior_4x(params, self.y_spatial_prior_reduction, + self.y_spatial_prior_adaptor_1, + self.y_spatial_prior_adaptor_2, + self.y_spatial_prior_adaptor_3, self.y_spatial_prior) + + x_hat = self.dec(y_hat, curr_q_dec).clamp_(0, 1) + return {"x_hat": x_hat} diff --git a/src/models/video_model.py b/DCVC-family/DCVC-RT/src/models/video_model.py similarity index 100% rename from src/models/video_model.py rename to DCVC-family/DCVC-RT/src/models/video_model.py diff --git a/DCVC-family/DCVC-RT/src/utils/common.py b/DCVC-family/DCVC-RT/src/utils/common.py new file mode 100644 index 0000000..a7599c0 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/utils/common.py @@ -0,0 +1,177 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import json +import os +from unittest.mock import patch + +import torch +from torch.nn.modules.utils import consume_prefix_in_state_dict_if_present +import numpy as np + + +def str2bool(v): + return str(v).lower() in ("yes", "y", "true", "t", "1") + + +def set_torch_env(): + os.environ['CUBLAS_WORKSPACE_CONFIG'] = ":4096:8" + torch.backends.cudnn.enabled = True + torch.backends.cudnn.benchmark = False + torch.use_deterministic_algorithms(True) + torch.manual_seed(0) + torch.set_num_threads(1) + np.random.seed(seed=0) + try: + # require pytorch >= 2.2.0 + torch.utils.deterministic.fill_uninitialized_memory = False + except Exception: # pylint: disable=W0718 + pass + + +def create_folder(path, print_if_create=False): + if not os.path.exists(path): + os.makedirs(path) + if print_if_create: + print(f"created folder: {path}") + + +def get_state_dict(ckpt_path): + ckpt = torch.load(ckpt_path, map_location=torch.device('cpu'), weights_only=True) + if "state_dict" in ckpt: + ckpt = ckpt['state_dict'] + if "net" in ckpt: + ckpt = ckpt["net"] + consume_prefix_in_state_dict_if_present(ckpt, prefix="module.") + return ckpt + + +@patch('json.encoder.c_make_encoder', None) +def dump_json(obj, fid, float_digits=-1, **kwargs): + of = json.encoder._make_iterencode # pylint: disable=W0212 + + def inner(*args, **kwargs): + args = list(args) + # fifth argument is float formater which we will replace + args[4] = lambda o: format(o, '.%df' % float_digits) + return of(*args, **kwargs) + + with patch('json.encoder._make_iterencode', wraps=inner): + json.dump(obj, fid, **kwargs) + + +def generate_log_json(frame_num, frame_pixel_num, test_time, frame_types, bits, psnrs, ssims, + verbose=False, avg_encoding_time=None, avg_decoding_time=None): + include_yuv = len(psnrs[0]) > 1 + assert not include_yuv or (len(psnrs[0]) == 4 and len(ssims[0]) == 4) + i_bits = 0 + i_psnr = 0 + i_psnr_y = 0 + i_psnr_u = 0 + i_psnr_v = 0 + i_ssim = 0 + i_ssim_y = 0 + i_ssim_u = 0 + i_ssim_v = 0 + p_bits = 0 + p_psnr = 0 + p_psnr_y = 0 + p_psnr_u = 0 + p_psnr_v = 0 + p_ssim = 0 + p_ssim_y = 0 + p_ssim_u = 0 + p_ssim_v = 0 + i_num = 0 + p_num = 0 + for idx in range(frame_num): + if frame_types[idx] == 0: + i_bits += bits[idx] + i_psnr += psnrs[idx][0] + i_ssim += ssims[idx][0] + i_num += 1 + if include_yuv: + i_psnr_y += psnrs[idx][1] + i_psnr_u += psnrs[idx][2] + i_psnr_v += psnrs[idx][3] + i_ssim_y += ssims[idx][1] + i_ssim_u += ssims[idx][2] + i_ssim_v += ssims[idx][3] + else: + p_bits += bits[idx] + p_psnr += psnrs[idx][0] + p_ssim += ssims[idx][0] + p_num += 1 + if include_yuv: + p_psnr_y += psnrs[idx][1] + p_psnr_u += psnrs[idx][2] + p_psnr_v += psnrs[idx][3] + p_ssim_y += ssims[idx][1] + p_ssim_u += ssims[idx][2] + p_ssim_v += ssims[idx][3] + + log_result = {} + log_result['frame_pixel_num'] = frame_pixel_num + log_result['i_frame_num'] = i_num + log_result['p_frame_num'] = p_num + log_result['ave_i_frame_bpp'] = i_bits / i_num / frame_pixel_num + log_result['ave_i_frame_psnr'] = i_psnr / i_num + log_result['ave_i_frame_msssim'] = i_ssim / i_num + if include_yuv: + log_result['ave_i_frame_psnr_y'] = i_psnr_y / i_num + log_result['ave_i_frame_psnr_u'] = i_psnr_u / i_num + log_result['ave_i_frame_psnr_v'] = i_psnr_v / i_num + log_result['ave_i_frame_msssim_y'] = i_ssim_y / i_num + log_result['ave_i_frame_msssim_u'] = i_ssim_u / i_num + log_result['ave_i_frame_msssim_v'] = i_ssim_v / i_num + if verbose: + log_result['frame_bpp'] = list(np.array(bits) / frame_pixel_num) + log_result['frame_psnr'] = [v[0] for v in psnrs] + log_result['frame_msssim'] = [v[0] for v in ssims] + log_result['frame_type'] = frame_types + if include_yuv: + log_result['frame_psnr_y'] = [v[1] for v in psnrs] + log_result['frame_psnr_u'] = [v[2] for v in psnrs] + log_result['frame_psnr_v'] = [v[3] for v in psnrs] + log_result['frame_msssim_y'] = [v[1] for v in ssims] + log_result['frame_msssim_u'] = [v[2] for v in ssims] + log_result['frame_msssim_v'] = [v[3] for v in ssims] + log_result['test_time'] = test_time + if p_num > 0: + total_p_pixel_num = p_num * frame_pixel_num + log_result['ave_p_frame_bpp'] = p_bits / total_p_pixel_num + log_result['ave_p_frame_psnr'] = p_psnr / p_num + log_result['ave_p_frame_msssim'] = p_ssim / p_num + if include_yuv: + log_result['ave_p_frame_psnr_y'] = p_psnr_y / p_num + log_result['ave_p_frame_psnr_u'] = p_psnr_u / p_num + log_result['ave_p_frame_psnr_v'] = p_psnr_v / p_num + log_result['ave_p_frame_msssim_y'] = p_ssim_y / p_num + log_result['ave_p_frame_msssim_u'] = p_ssim_u / p_num + log_result['ave_p_frame_msssim_v'] = p_ssim_v / p_num + else: + log_result['ave_p_frame_bpp'] = 0 + log_result['ave_p_frame_psnr'] = 0 + log_result['ave_p_frame_msssim'] = 0 + if include_yuv: + log_result['ave_p_frame_psnr_y'] = 0 + log_result['ave_p_frame_psnr_u'] = 0 + log_result['ave_p_frame_psnr_v'] = 0 + log_result['ave_p_frame_msssim_y'] = 0 + log_result['ave_p_frame_msssim_u'] = 0 + log_result['ave_p_frame_msssim_v'] = 0 + log_result['ave_all_frame_bpp'] = (i_bits + p_bits) / (frame_num * frame_pixel_num) + log_result['ave_all_frame_psnr'] = (i_psnr + p_psnr) / frame_num + log_result['ave_all_frame_msssim'] = (i_ssim + p_ssim) / frame_num + if avg_encoding_time is not None and avg_decoding_time is not None: + log_result['avg_frame_encoding_time'] = avg_encoding_time + log_result['avg_frame_decoding_time'] = avg_decoding_time + if include_yuv: + log_result['ave_all_frame_psnr_y'] = (i_psnr_y + p_psnr_y) / frame_num + log_result['ave_all_frame_psnr_u'] = (i_psnr_u + p_psnr_u) / frame_num + log_result['ave_all_frame_psnr_v'] = (i_psnr_v + p_psnr_v) / frame_num + log_result['ave_all_frame_msssim_y'] = (i_ssim_y + p_ssim_y) / frame_num + log_result['ave_all_frame_msssim_u'] = (i_ssim_u + p_ssim_u) / frame_num + log_result['ave_all_frame_msssim_v'] = (i_ssim_v + p_ssim_v) / frame_num + + return log_result diff --git a/DCVC-family/DCVC-RT/src/utils/metrics.py b/DCVC-family/DCVC-RT/src/utils/metrics.py new file mode 100644 index 0000000..869a9ab --- /dev/null +++ b/DCVC-family/DCVC-RT/src/utils/metrics.py @@ -0,0 +1,96 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import numpy as np +from scipy import signal +from scipy import ndimage + + +def fspecial_gauss(size, sigma): + x, y = np.mgrid[-size // 2 + 1:size // 2 + 1, -size // 2 + 1:size // 2 + 1] + g = np.exp(-((x**2 + y**2) / (2.0 * sigma**2))) + return g / g.sum() + + +def calc_ssim(img1, img2, data_range=255): + img1 = img1.astype(np.float64) + img2 = img2.astype(np.float64) + size = 11 + sigma = 1.5 + window = fspecial_gauss(size, sigma) + K1 = 0.01 + K2 = 0.03 + C1 = (K1 * data_range)**2 + C2 = (K2 * data_range)**2 + mu1 = signal.fftconvolve(window, img1, mode='valid') + mu2 = signal.fftconvolve(window, img2, mode='valid') + mu1_sq = mu1 * mu1 + mu2_sq = mu2 * mu2 + mu1_mu2 = mu1 * mu2 + sigma1_sq = signal.fftconvolve(window, img1 * img1, mode='valid') - mu1_sq + sigma2_sq = signal.fftconvolve(window, img2 * img2, mode='valid') - mu2_sq + sigma12 = signal.fftconvolve(window, img1 * img2, mode='valid') - mu1_mu2 + + return (((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * + (sigma1_sq + sigma2_sq + C2)), + (2.0 * sigma12 + C2) / (sigma1_sq + sigma2_sq + C2)) + + +def calc_msssim(img1, img2, data_range=255): + ''' + img1 and img2 are 2D arrays + ''' + level = 5 + weight = np.array([0.0448, 0.2856, 0.3001, 0.2363, 0.1333]) + height, width = img1.shape + if height < 176 or width < 176: + # according to HM implementation + level = 4 + weight = np.array([0.0517, 0.3295, 0.3462, 0.2726]) + if height < 88 or width < 88: + assert False + downsample_filter = np.ones((2, 2)) / 4.0 + im1 = img1.astype(np.float64) + im2 = img2.astype(np.float64) + mssim = np.array([]) + mcs = np.array([]) + for _ in range(level): + ssim_map, cs_map = calc_ssim(im1, im2, data_range=data_range) + mssim = np.append(mssim, ssim_map.mean()) + mcs = np.append(mcs, cs_map.mean()) + filtered_im1 = ndimage.filters.convolve(im1, downsample_filter, + mode='reflect') + filtered_im2 = ndimage.filters.convolve(im2, downsample_filter, + mode='reflect') + im1 = filtered_im1[::2, ::2] + im2 = filtered_im2[::2, ::2] + return (np.prod(mcs[0:level - 1]**weight[0:level - 1]) * + (mssim[level - 1]**weight[level - 1])) + + +def calc_msssim_rgb(img1, img2, data_range=255): + ''' + img1 and img2 are arrays with 3xHxW + ''' + msssim = 0 + for i in range(3): + msssim += calc_msssim(img1[i, :, :], img2[i, :, :], data_range) + return msssim / 3 + + +def calc_psnr(img1, img2, data_range=255): + ''' + img1 and img2 are arrays with same shape + ''' + img1 = img1.astype(np.float64) + img2 = img2.astype(np.float64) + mse = np.mean(np.square(img1 - img2)) + if np.isnan(mse) or np.isinf(mse): + return -999.9 + if mse > 1e-10: + psnr = 10 * np.log10(data_range * data_range / mse) + else: + psnr = 999.9 + if psnr > 99.9: + psnr = 99.9 + return psnr diff --git a/DCVC-family/DCVC-RT/src/utils/stream_helper.py b/DCVC-family/DCVC-RT/src/utils/stream_helper.py new file mode 100644 index 0000000..1450782 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/utils/stream_helper.py @@ -0,0 +1,217 @@ +# Copyright 2020 InterDigital Communications, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import enum +import struct +from pathlib import Path + + +def filesize(filepath: str) -> int: + if not Path(filepath).is_file(): + raise ValueError(f'Invalid file "{filepath}".') + return Path(filepath).stat().st_size + + +def write_uints(fd, values, fmt=">{:d}I"): + fd.write(struct.pack(fmt.format(len(values)), *values)) + return len(values) * 4 + + +def write_uchars(fd, values, fmt=">{:d}B"): + fd.write(struct.pack(fmt.format(len(values)), *values)) + return len(values) + + +def read_uints(fd, n, fmt=">{:d}I"): + sz = struct.calcsize("I") + return struct.unpack(fmt.format(n), fd.read(n * sz)) + + +def read_uchars(fd, n, fmt=">{:d}B"): + sz = struct.calcsize("B") + return struct.unpack(fmt.format(n), fd.read(n * sz)) + + +def write_bytes(fd, values, fmt=">{:d}s"): + if len(values) == 0: + return 0 + fd.write(struct.pack(fmt.format(len(values)), values)) + return len(values) + + +def read_bytes(fd, n, fmt=">{:d}s"): + sz = struct.calcsize("s") + return struct.unpack(fmt.format(n), fd.read(n * sz))[0] + + +def write_ushorts(fd, values, fmt=">{:d}H"): + fd.write(struct.pack(fmt.format(len(values)), *values)) + return len(values) * 2 + + +def read_ushorts(fd, n, fmt=">{:d}H"): + sz = struct.calcsize("H") + return struct.unpack(fmt.format(n), fd.read(n * sz)) + + +def write_uint_adaptive(f, a): + if a < (1 << 7): + a0 = (a >> 0) & 0xff + a0 = a0 | (0x00 << 7) + write_uchars(f, (a0,)) + return 1 + + if a < (1 << 14): + a0 = (a >> 0) & 0xff + a1 = (a >> 8) & 0xff + a1 = a1 | (0x02 << 6) + write_uchars(f, (a1, a0)) + return 2 + + assert a < (1 << 30) + a0 = (a >> 0) & 0xff + a1 = (a >> 8) & 0xff + a2 = (a >> 16) & 0xff + a3 = (a >> 24) & 0xff + a3 = a3 | (0x03 << 6) + write_uchars(f, (a3, a2, a1, a0)) + return 4 + + +def read_uint_adaptive(f): + a3 = read_uchars(f, 1)[0] + if (a3 >> 7) == 0: + return a3 + + a2 = read_uchars(f, 1)[0] + + if (a3 >> 6) == 0x02: + a3 = a3 & 0x3f + return (a3 << 8) + a2 + a3 = a3 & 0x3f + a1 = read_uchars(f, 1)[0] + a0 = read_uchars(f, 1)[0] + return (a3 << 24) + (a2 << 16) + (a1 << 8) + a0 + + +class NalType(enum.IntEnum): + NAL_SPS = 0 + NAL_I = 1 + NAL_P = 2 + + +class SPSHelper(): + def __init__(self): + super().__init__() + self.spss = [] + + def get_sps_id(self, target_sps): + min_id = -1 + for sps in self.spss: + if sps['height'] == target_sps['height'] and sps['width'] == target_sps['width'] and \ + sps['use_ada_i'] == target_sps['use_ada_i'] and \ + sps['ec_part'] == target_sps['ec_part']: + return sps['sps_id'], False + if sps['sps_id'] > min_id: + min_id = sps['sps_id'] + assert min_id < 15 + sps = target_sps.copy() + sps['sps_id'] = min_id + 1 + self.spss.append(sps) + return sps['sps_id'], True + + def add_sps_by_id(self, sps): + for i in range(len(self.spss)): + if self.spss[i]['sps_id'] == sps['sps_id']: + self.spss[i] = sps.copy() + return + self.spss.append(sps.copy()) + + def get_sps_by_id(self, sps_id): + for sps in self.spss: + if sps['sps_id'] == sps_id: + return sps + return None + + +def write_sps(f, sps): + # nal_type(4), sps_id(4) + # height (variable) + # width (vairable) + # 0(6), ec_part(1) use_ada_i(1) + assert sps['sps_id'] < 16 + assert sps['use_ada_i'] < 2 + written = 0 + flag = int((NalType.NAL_SPS << 4) + sps['sps_id']) + written += write_uchars(f, (flag,)) + written += write_uint_adaptive(f, sps['height']) + written += write_uint_adaptive(f, sps['width']) + flag = (sps['ec_part'] << 2) + sps['use_ada_i'] + written += write_uchars(f, (flag,)) + return written + + +def read_header(f): + header = {} + flag = read_uchars(f, 1)[0] + nal_type = flag >> 4 + header['nal_type'] = NalType(nal_type) + if nal_type < 3: + header['sps_id'] = flag & 0x0f + return header + + frame_num_minus1 = flag & 0x0f + frame_num = frame_num_minus1 + 1 + header['frame_num'] = frame_num + sps_ids = [] + for _ in range(0, frame_num, 2): + flag = read_uchars(f, 1)[0] + sps_ids.append(flag >> 4) + sps_ids.append(flag & 0x0f) + sps_ids = sps_ids[:frame_num] + header['sps_ids'] = sps_ids + return header + + +def read_sps_remaining(f, sps_id): + sps = {} + sps['sps_id'] = sps_id + sps['height'] = read_uint_adaptive(f) + sps['width'] = read_uint_adaptive(f) + flag = read_uchars(f, 1)[0] + sps['ec_part'] = (flag >> 2) & 0x01 + sps['use_ada_i'] = flag & 0x01 + return sps + + +def write_ip(f, is_i_frame, sps_id, qp, bit_stream): + written = 0 + flag = (int(NalType.NAL_I if is_i_frame else NalType.NAL_P) << 4) + sps_id + written += write_uchars(f, (flag,)) + assert qp < 256 and qp >= 0 + flag = qp + written += write_uchars(f, (flag,)) + # we write all the streams in the same file, thus, we need to write the per-frame length + # if packed independently, we do not need to write it + written += write_uint_adaptive(f, len(bit_stream)) + written += write_bytes(f, bit_stream) + return written + + +def read_ip_remaining(f): + flag = read_uchars(f, 1)[0] + qp = flag + stream_length = read_uint_adaptive(f) + bit_stream = read_bytes(f, stream_length) + return qp, bit_stream diff --git a/DCVC-family/DCVC-RT/src/utils/transforms.py b/DCVC-family/DCVC-RT/src/utils/transforms.py new file mode 100644 index 0000000..9b96d17 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/utils/transforms.py @@ -0,0 +1,63 @@ +import numpy as np +import scipy.ndimage +import torch +import torch.nn.functional as F + + +YCBCR_WEIGHTS = { + # Spec: (K_r, K_g, K_b) with K_g = 1 - K_r - K_b + "ITU-R_BT.709": (0.2126, 0.7152, 0.0722) +} + + +def ycbcr420_to_444_np(y, uv, order=0, separate=False): + ''' + y is 1xhxw Y float numpy array + uv is 2x(h/2)x(w/2) UV float numpy array + order: 0 nearest neighbor (default), 1: binear + return value is 3xhxw YCbCr float numpy array + ''' + uv = scipy.ndimage.zoom(uv, (1, 2, 2), order=order) + if separate: + return y, uv + yuv = np.concatenate((y, uv), axis=0) + return yuv + + +def rgb2ycbcr(rgb, is_bgr=False): + if is_bgr: + b, g, r = rgb.chunk(3, -3) + else: + r, g, b = rgb.chunk(3, -3) + Kr, Kg, Kb = YCBCR_WEIGHTS["ITU-R_BT.709"] + y = Kr * r + Kg * g + Kb * b + cb = 0.5 * (b - y) / (1 - Kb) + 0.5 + cr = 0.5 * (r - y) / (1 - Kr) + 0.5 + ycbcr = torch.cat((y, cb, cr), dim=-3) + ycbcr = torch.clamp(ycbcr, 0., 1.) + return ycbcr + + +def ycbcr2rgb(ycbcr, is_bgr=False, clamp=True): + y, cb, cr = ycbcr.chunk(3, -3) + Kr, Kg, Kb = YCBCR_WEIGHTS["ITU-R_BT.709"] + r = y + (2 - 2 * Kr) * (cr - 0.5) + b = y + (2 - 2 * Kb) * (cb - 0.5) + g = (y - Kr * r - Kb * b) / Kg + if is_bgr: + rgb = torch.cat((b, g, r), dim=-3) + else: + rgb = torch.cat((r, g, b), dim=-3) + if clamp: + rgb = torch.clamp(rgb, 0., 1.) + return rgb + + +def yuv_444_to_420(yuv): + def _downsample(tensor): + return F.avg_pool2d(tensor, kernel_size=2, stride=2) + + y = yuv[:, :1, :, :] + uv = yuv[:, 1:, :, :] + + return y, _downsample(uv) diff --git a/DCVC-family/DCVC-RT/src/utils/video_reader.py b/DCVC-family/DCVC-RT/src/utils/video_reader.py new file mode 100644 index 0000000..a251845 --- /dev/null +++ b/DCVC-family/DCVC-RT/src/utils/video_reader.py @@ -0,0 +1,90 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import os + +import numpy as np +from PIL import Image + + +class PNGReader(): + def __init__(self, src_path, width, height, start_num=1): + self.eof = False + self.src_path = src_path + self.width = width + self.height = height + pngs = os.listdir(self.src_path) + if 'im1.png' in pngs: + self.padding = 1 + elif 'im00001.png' in pngs: + self.padding = 5 + else: + raise ValueError('unknown image naming convention; please specify') + self.current_frame_index = start_num + + def read_one_frame(self): + # rgb: 3xhxw uint8 numpy array + if self.eof: + return None + + png_path = os.path.join(self.src_path, + f"im{str(self.current_frame_index).zfill(self.padding)}.png" + ) + if not os.path.exists(png_path): + self.eof = True + return None + + rgb = Image.open(png_path).convert('RGB') + rgb = np.asarray(rgb).astype(np.uint8).transpose(2, 0, 1) + _, height, width = rgb.shape + assert height == self.height + assert width == self.width + + self.current_frame_index += 1 + return rgb + + def close(self): + self.current_frame_index = 1 + + +class YUV420Reader(): + def __init__(self, src_path, width, height, skip_frame=0): + self.eof = False + if not src_path.endswith('.yuv'): + src_path = src_path + '.yuv' + self.src_path = src_path + + self.y_size = width * height + self.y_width = width + self.y_height = height + self.uv_size = width * height // 2 + self.uv_width = width // 2 + self.uv_height = height // 2 + # pylint: disable=R1732 + self.file = open(src_path, "rb") + # pylint: enable=R1732 + skipped_frame = 0 + while not self.eof and skipped_frame < skip_frame: + y = self.file.read(self.y_size) + uv = self.file.read(self.uv_size) + if not y or not uv: + self.eof = True + skipped_frame += 1 + + def read_one_frame(self): + # y: 1xhxw uint8 numpy array + # uv: 2x(h/2)x(w/2) uint8 numpy array + if self.eof: + return None, None + y = self.file.read(self.y_size) + uv = self.file.read(self.uv_size) + if not y or not uv: + self.eof = True + return None, None + y = np.frombuffer(y, dtype=np.uint8).copy().reshape(1, self.y_height, self.y_width) + uv = np.frombuffer(uv, dtype=np.uint8).copy().reshape(2, self.uv_height, self.uv_width) + + return y, uv + + def close(self): + self.file.close() diff --git a/DCVC-family/DCVC-RT/src/utils/video_writer.py b/DCVC-family/DCVC-RT/src/utils/video_writer.py new file mode 100644 index 0000000..d61089d --- /dev/null +++ b/DCVC-family/DCVC-RT/src/utils/video_writer.py @@ -0,0 +1,52 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import os + +from PIL import Image + + +class PNGWriter(): + def __init__(self, dst_path, width, height): + self.dst_path = dst_path + self.width = width + self.height = height + self.padding = 5 + self.current_frame_index = 1 + os.makedirs(dst_path, exist_ok=True) + + def write_one_frame(self, rgb): + # rgb: 3xhxw uint8 numpy array + rgb = rgb.transpose(1, 2, 0) + + png_path = os.path.join(self.dst_path, + f"im{str(self.current_frame_index).zfill(self.padding)}.png" + ) + Image.fromarray(rgb).save(png_path) + + self.current_frame_index += 1 + + def close(self): + self.current_frame_index = 1 + + +class YUV420Writer(): + def __init__(self, dst_path, width, height): + if not dst_path.endswith('.yuv'): + dst_path = dst_path + '/out.yuv' + self.dst_path = dst_path + self.width = width + self.height = height + + # pylint: disable=R1732 + self.file = open(dst_path, "wb") + # pylint: enable=R1732 + + def write_one_frame(self, y, uv): + # y: 1xhxw uint8 numpy array + # uv: 2x(h/2)x(w/2) uint8 numpy array + self.file.write(y.tobytes()) + self.file.write(uv.tobytes()) + + def close(self): + self.file.close() diff --git a/DCVC-family/DCVC-RT/test_video.py b/DCVC-family/DCVC-RT/test_video.py new file mode 100644 index 0000000..8658569 --- /dev/null +++ b/DCVC-family/DCVC-RT/test_video.py @@ -0,0 +1,541 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import argparse +import concurrent.futures +import io +import json +import multiprocessing +import os +import time + +import torch +import numpy as np +from tqdm import tqdm + +from src.layers.cuda_inference import replicate_pad +from src.models.video_model import DMC +from src.models.image_model import DMCI +from src.utils.common import str2bool, create_folder, generate_log_json, get_state_dict, \ + dump_json, set_torch_env +from src.utils.stream_helper import SPSHelper, NalType, write_sps, read_header, \ + read_sps_remaining, read_ip_remaining, write_ip +from src.utils.video_reader import PNGReader, YUV420Reader +from src.utils.video_writer import PNGWriter, YUV420Writer +from src.utils.metrics import calc_psnr, calc_msssim, calc_msssim_rgb +from src.utils.transforms import rgb2ycbcr, ycbcr2rgb, yuv_444_to_420, ycbcr420_to_444_np + + +def parse_args(): + parser = argparse.ArgumentParser(description="Example testing script") + + parser.add_argument('--force_zero_thres', type=float, default=None, required=False) + parser.add_argument('--model_path_i', type=str) + parser.add_argument('--model_path_p', type=str) + parser.add_argument('--rate_num', type=int, default=4) + parser.add_argument('--qp_i', type=int, nargs="+") + parser.add_argument('--qp_p', type=int, nargs="+") + parser.add_argument("--force_intra", type=str2bool, default=False) + parser.add_argument("--force_frame_num", type=int, default=-1) + parser.add_argument("--force_intra_period", type=int, default=-1) + parser.add_argument('--reset_interval', type=int, default=32, required=False) + parser.add_argument('--test_config', type=str, required=True) + parser.add_argument('--force_root_path', type=str, default=None, required=False) + parser.add_argument("--worker", "-w", type=int, default=1, help="worker number") + parser.add_argument("--cuda", type=str2bool, default=False) + parser.add_argument('--cuda_idx', type=int, nargs="+", help='GPU indexes to use') + parser.add_argument('--calc_ssim', type=str2bool, default=False, required=False) + parser.add_argument('--write_stream', type=str2bool, default=False) + parser.add_argument('--check_existing', type=str2bool, default=False) + parser.add_argument('--stream_path', type=str, default="out_bin") + parser.add_argument('--save_decoded_frame', type=str2bool, default=False) + parser.add_argument('--output_path', type=str, required=True) + parser.add_argument('--verbose_json', type=str2bool, default=False) + parser.add_argument('--verbose', type=int, default=0) + + args = parser.parse_args() + return args + + +def np_image_to_tensor(img, device): + image = torch.from_numpy(img).to(device=device).to(dtype=torch.float32) / 255.0 + image = image.unsqueeze(0) + return image + + +def get_src_reader(args): + if args['src_type'] == 'png': + src_reader = PNGReader(args['src_path'], args['src_width'], args['src_height']) + elif args['src_type'] == 'yuv420': + src_reader = YUV420Reader(args['src_path'], args['src_width'], args['src_height']) + return src_reader + + +def get_src_frame(args, src_reader, device): + if args['src_type'] == 'yuv420': + y, uv = src_reader.read_one_frame() + yuv = ycbcr420_to_444_np(y, uv) + x = np_image_to_tensor(yuv, device) + y = y[0, :, :] + u = uv[0, :, :] + v = uv[1, :, :] + rgb = None + else: + assert args['src_type'] == 'png' + rgb = src_reader.read_one_frame() + x = np_image_to_tensor(rgb, device) + x = rgb2ycbcr(x) + y, u, v = None, None, None + + x = x.to(torch.float16) + return x, y, u, v, rgb + + +def get_distortion(args, x_hat, y, u, v, rgb): + if args['src_type'] == 'yuv420': + y_rec, uv_rec = yuv_444_to_420(x_hat) + y_rec = torch.clamp(y_rec * 255, 0, 255).squeeze(0).cpu().numpy() + uv_rec = torch.clamp(uv_rec * 255, 0, 255).squeeze(0).cpu().numpy() + y_rec = y_rec[0, :, :] + u_rec = uv_rec[0, :, :] + v_rec = uv_rec[1, :, :] + psnr_y = calc_psnr(y, y_rec) + psnr_u = calc_psnr(u, u_rec) + psnr_v = calc_psnr(v, v_rec) + psnr = (6 * psnr_y + psnr_u + psnr_v) / 8 + if args['calc_ssim']: + ssim_y = calc_msssim(y, y_rec) + ssim_u = calc_msssim(u, u_rec) + ssim_v = calc_msssim(v, v_rec) + else: + ssim_y, ssim_u, ssim_v = 0., 0., 0. + ssim = (6 * ssim_y + ssim_u + ssim_v) / 8 + + curr_psnr = [psnr, psnr_y, psnr_u, psnr_v] + curr_ssim = [ssim, ssim_y, ssim_u, ssim_v] + else: + assert args['src_type'] == 'png' + rgb_rec = ycbcr2rgb(x_hat) + rgb_rec = torch.clamp(rgb_rec * 255, 0, 255).squeeze(0).cpu().numpy() + psnr = calc_psnr(rgb, rgb_rec) + if args['calc_ssim']: + msssim = calc_msssim_rgb(rgb, rgb_rec) + else: + msssim = 0. + curr_psnr = [psnr] + curr_ssim = [msssim] + return curr_psnr, curr_ssim + + +def run_one_point_with_stream(p_frame_net, i_frame_net, args): + if args['check_existing'] and os.path.exists(args['curr_json_path']) and \ + os.path.exists(args['curr_bin_path']): + with open(args['curr_json_path']) as f: + log_result = json.load(f) + if log_result['i_frame_num'] + log_result['p_frame_num'] == args['frame_num']: + return log_result + print(f"incorrect log for {args['curr_json_path']}, try to rerun.") + + frame_num = args['frame_num'] + save_decoded_frame = args['save_decoded_frame'] + verbose = args['verbose'] + reset_interval = args['reset_interval'] + intra_period = args['intra_period'] + verbose_json = args['verbose_json'] + device = next(i_frame_net.parameters()).device + + src_reader = get_src_reader(args) + pic_height = args['src_height'] + pic_width = args['src_width'] + padding_r, padding_b = DMCI.get_padding_size(pic_height, pic_width, 16) + + use_two_entropy_coders = pic_height * pic_width > 1280 * 720 + i_frame_net.set_use_two_entropy_coders(use_two_entropy_coders) + p_frame_net.set_use_two_entropy_coders(use_two_entropy_coders) + + frame_types = [] + psnrs = [] + msssims = [] + bits = [] + + start_time = time.time() + encoding_time = [] + decoding_time = [] + index_map = [0, 1, 0, 2, 0, 2, 0, 2] + + output_buff = io.BytesIO() + sps_helper = SPSHelper() + + p_frame_net.set_curr_poc(0) + with torch.no_grad(): + last_qp = 0 + for frame_idx in range(frame_num): + x, y, u, v, rgb = get_src_frame(args, src_reader, device) + + torch.cuda.synchronize(device=device) + frame_start_time = time.time() + + # pad if necessary + x_padded = replicate_pad(x, padding_b, padding_r) + + is_i_frame = False + if frame_idx == 0 or (intra_period > 0 and frame_idx % intra_period == 0): + is_i_frame = True + curr_qp = args['qp_i'] + sps = { + 'sps_id': -1, + 'height': pic_height, + 'width': pic_width, + 'ec_part': 1 if use_two_entropy_coders else 0, + 'use_ada_i': 0, + } + encoded = i_frame_net.compress(x_padded, args['qp_i']) + p_frame_net.clear_dpb() + p_frame_net.add_ref_frame(None, encoded['x_hat']) + frame_types.append(0) + else: + fa_idx = index_map[frame_idx % 8] + if reset_interval > 0 and frame_idx % reset_interval == 1: + use_ada_i = 1 + p_frame_net.prepare_feature_adaptor_i(last_qp) + else: + use_ada_i = 0 + curr_qp = p_frame_net.shift_qp(args['qp_p'], fa_idx) + sps = { + 'sps_id': -1, + 'height': pic_height, + 'width': pic_width, + 'ec_part': 1 if use_two_entropy_coders else 0, + 'use_ada_i': use_ada_i, + } + + encoded = p_frame_net.compress(x_padded, curr_qp) + last_qp = curr_qp + frame_types.append(1) + + sps_id, sps_new = sps_helper.get_sps_id(sps) + sps['sps_id'] = sps_id + sps_bytes = 0 + if sps_new: + sps_bytes = write_sps(output_buff, sps) + if verbose >= 2: + print("new sps", sps) + stream_bytes = write_ip(output_buff, is_i_frame, sps_id, curr_qp, encoded['bit_stream']) + bits.append(stream_bytes * 8 + sps_bytes * 8) + + torch.cuda.synchronize(device=device) + frame_end_time = time.time() + + frame_time = frame_end_time - frame_start_time + encoding_time.append(frame_time) + + if verbose >= 2: + print(f"frame {frame_idx} encoded, {frame_time * 1000:.3f} ms, " + f"bits: {bits[-1]}") + + src_reader.close() + with open(args['curr_bin_path'], "wb") as output_file: + bytes_buffer = output_buff.getbuffer() + output_file.write(bytes_buffer) + total_bytes = bytes_buffer.nbytes + bytes_buffer.release() + total_kbps = int(total_bytes * 8 / (frame_num / 30) / 1000) # assume 30 fps + output_buff.close() + sps_helper = SPSHelper() + input_file = open(args['curr_bin_path'], "rb") + with open(args['curr_bin_path'], "rb") as input_file: + input_buff = io.BytesIO(input_file.read()) + decoded_frame_number = 0 + src_reader = get_src_reader(args) + + if save_decoded_frame: + if args['src_type'] == 'png': + recon_writer = PNGWriter(args['bin_folder'], args['src_width'], args['src_height']) + elif args['src_type'] == 'yuv420': + output_yuv_path = args['curr_rec_path'].replace('.yuv', f'_{total_kbps}kbps.yuv') + recon_writer = YUV420Writer(output_yuv_path, args['src_width'], args['src_height']) + + p_frame_net.set_curr_poc(0) + with torch.no_grad(): + while decoded_frame_number < frame_num: + x, y, u, v, rgb = get_src_frame(args, src_reader, device) + torch.cuda.synchronize(device=device) + frame_start_time = time.time() + + header = read_header(input_buff) + while header['nal_type'] == NalType.NAL_SPS: + sps = read_sps_remaining(input_buff, header['sps_id']) + sps_helper.add_sps_by_id(sps) + if verbose >= 2: + print("new sps", sps) + header = read_header(input_buff) + continue + sps_id = header['sps_id'] + + sps = sps_helper.get_sps_by_id(sps_id) + qp, bit_stream = read_ip_remaining(input_buff) + + if header['nal_type'] == NalType.NAL_I: + decoded = i_frame_net.decompress(bit_stream, sps, qp) + p_frame_net.clear_dpb() + p_frame_net.add_ref_frame(None, decoded['x_hat']) + elif header['nal_type'] == NalType.NAL_P: + if sps['use_ada_i']: + p_frame_net.reset_ref_feature() + decoded = p_frame_net.decompress(bit_stream, sps, qp) + + recon_frame = decoded['x_hat'] + x_hat = recon_frame[:, :, :pic_height, :pic_width] + + torch.cuda.synchronize(device=device) + frame_end_time = time.time() + + frame_time = frame_end_time - frame_start_time + decoding_time.append(frame_time) + + curr_psnr, curr_ssim = get_distortion(args, x_hat, y, u, v, rgb) + psnrs.append(curr_psnr) + msssims.append(curr_ssim) + + if verbose >= 2: + stream_length = 0 if bit_stream is None else len(bit_stream) * 8 + print(f"frame {decoded_frame_number} decoded, {frame_time * 1000:.3f} ms, " + f"bits: {stream_length}, PSNR: {curr_psnr[0]:.4f} ") + + if save_decoded_frame: + if args['src_type'] == 'yuv420': + y_rec, uv_rec = yuv_444_to_420(x_hat) + y_rec = torch.clamp(y_rec * 255, 0, 255).round().to(dtype=torch.uint8) + y_rec = y_rec.squeeze(0).cpu().numpy() + uv_rec = torch.clamp(uv_rec * 255, 0, 255).to(dtype=torch.uint8) + uv_rec = uv_rec.squeeze(0).cpu().numpy() + recon_writer.write_one_frame(y_rec, uv_rec) + else: + assert args['src_type'] == 'png' + rgb_rec = ycbcr2rgb(x_hat) + rgb_rec = torch.clamp(rgb_rec * 255, 0, 255).round().to(dtype=torch.uint8) + rgb_rec = rgb_rec.squeeze(0).cpu().numpy() + recon_writer.write_one_frame(rgb_rec) + decoded_frame_number += 1 + input_buff.close() + src_reader.close() + + if save_decoded_frame: + recon_writer.close() + + test_time = time.time() - start_time + test_time_frame_numuber = len(encoding_time) + time_bypass_frame_num = 10 # bypass the first 10 frames as warmup + if verbose >= 1 and test_time_frame_numuber > time_bypass_frame_num: + encoding_time = encoding_time[time_bypass_frame_num:] + decoding_time = decoding_time[time_bypass_frame_num:] + avg_encoding_time = sum(encoding_time)/len(encoding_time) + avg_decoding_time = sum(decoding_time)/len(decoding_time) + print(f"encoding/decoding {test_time_frame_numuber} frames, " + f"average encoding time {avg_encoding_time * 1000:.3f} ms, " + f"average decoding time {avg_decoding_time * 1000:.3f} ms.") + else: + avg_encoding_time = None + avg_decoding_time = None + + log_result = generate_log_json(frame_num, pic_height * pic_width, test_time, + frame_types, bits, psnrs, msssims, verbose=verbose_json, + avg_encoding_time=avg_encoding_time, + avg_decoding_time=avg_decoding_time,) + with open(args['curr_json_path'], 'w') as fp: + json.dump(log_result, fp, indent=2) + return log_result + + +i_frame_net = None # the model is initialized after each process is spawn, thus OK for multiprocess +p_frame_net = None + + +def worker(args): + global i_frame_net + global p_frame_net + + sub_dir_name = args['seq'] + bin_folder = os.path.join(args['stream_path'], args['ds_name']) + assert args['write_stream'], "" + create_folder(bin_folder, True) + + args['src_path'] = os.path.join(args['dataset_path'], sub_dir_name) + args['bin_folder'] = bin_folder + args['curr_bin_path'] = os.path.join(bin_folder, + f"{args['seq']}_q{args['qp_i']}.bin") + args['curr_rec_path'] = args['curr_bin_path'].replace('.bin', '.yuv') + args['curr_json_path'] = args['curr_bin_path'].replace('.bin', '.json') + + result = run_one_point_with_stream(p_frame_net, i_frame_net, args) + + result['ds_name'] = args['ds_name'] + result['seq'] = args['seq'] + result['rate_idx'] = args['rate_idx'] + result['qp_i'] = args['qp_i'] + result['qp_p'] = args['qp_p'] if 'qp_p' in args else args['qp_i'] + + return result + + +def init_func(args, gpu_num): + set_torch_env() + + process_name = multiprocessing.current_process().name + process_idx = int(process_name[process_name.rfind('-') + 1:]) + gpu_id = -1 + if gpu_num > 0: + gpu_id = process_idx % gpu_num + if gpu_id >= 0: + if args.cuda_idx is not None: + gpu_id = args.cuda_idx[gpu_id] + os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) + device = "cuda:0" + else: + device = "cpu" + + global i_frame_net + i_frame_net = DMCI() + i_state_dict = get_state_dict(args.model_path_i) + i_frame_net.load_state_dict(i_state_dict) + i_frame_net = i_frame_net.to(device) + i_frame_net.eval() + i_frame_net.update(args.force_zero_thres) + i_frame_net.half() + + global p_frame_net + p_frame_net = DMC() + if not args.force_intra: + p_state_dict = get_state_dict(args.model_path_p) + p_frame_net.load_state_dict(p_state_dict) + p_frame_net = p_frame_net.to(device) + p_frame_net.eval() + p_frame_net.update(args.force_zero_thres) + p_frame_net.half() + + +def main(): + begin_time = time.time() + + args = parse_args() + + if args.force_zero_thres is not None and args.force_zero_thres < 0: + args.force_zero_thres = None + + if args.cuda_idx is not None: + cuda_device = ','.join([str(s) for s in args.cuda_idx]) + os.environ['CUDA_VISIBLE_DEVICES'] = cuda_device + + worker_num = args.worker + assert worker_num >= 1 + + with open(args.test_config) as f: + config = json.load(f) + + gpu_num = 0 + if args.cuda: + gpu_num = torch.cuda.device_count() + + multiprocessing.set_start_method("spawn") + threadpool_executor = concurrent.futures.ProcessPoolExecutor(max_workers=worker_num, + initializer=init_func, + initargs=(args, gpu_num)) + objs = [] + + count_frames = 0 + count_sequences = 0 + + rate_num = args.rate_num + qp_i = [] + if args.qp_i is not None: + assert len(args.qp_i) == rate_num + qp_i = args.qp_i + else: + assert 2 <= rate_num <= DMC.get_qp_num() + for i in np.linspace(0, DMC.get_qp_num() - 1, num=rate_num): + qp_i.append(int(i+0.5)) + + if not args.force_intra: + if args.qp_p is not None: + assert len(args.qp_p) == rate_num + qp_p = args.qp_p + else: + qp_p = qp_i + + print(f"testing {rate_num} rates, using qp: ", end='') + for q in qp_i: + print(f"{q}, ", end='') + print() + + root_path = args.force_root_path if args.force_root_path is not None else config['root_path'] + config = config['test_classes'] + for ds_name in config: + if config[ds_name]['test'] == 0: + continue + for seq in config[ds_name]['sequences']: + count_sequences += 1 + for rate_idx in range(rate_num): + cur_args = {} + cur_args['rate_idx'] = rate_idx + cur_args['qp_i'] = qp_i[rate_idx] + if not args.force_intra: + cur_args['qp_p'] = qp_p[rate_idx] + cur_args['force_intra'] = args.force_intra + cur_args['reset_interval'] = args.reset_interval + cur_args['seq'] = seq + cur_args['src_type'] = config[ds_name]['src_type'] + cur_args['src_height'] = config[ds_name]['sequences'][seq]['height'] + cur_args['src_width'] = config[ds_name]['sequences'][seq]['width'] + cur_args['intra_period'] = config[ds_name]['sequences'][seq]['intra_period'] + if args.force_intra: + cur_args['intra_period'] = 1 + if args.force_intra_period > 0: + cur_args['intra_period'] = args.force_intra_period + cur_args['frame_num'] = config[ds_name]['sequences'][seq]['frames'] + if args.force_frame_num > 0: + cur_args['frame_num'] = args.force_frame_num + cur_args['calc_ssim'] = args.calc_ssim + cur_args['dataset_path'] = os.path.join(root_path, config[ds_name]['base_path']) + cur_args['write_stream'] = args.write_stream + cur_args['check_existing'] = args.check_existing + cur_args['stream_path'] = args.stream_path + cur_args['save_decoded_frame'] = args.save_decoded_frame + cur_args['ds_name'] = ds_name + cur_args['verbose'] = args.verbose + cur_args['verbose_json'] = args.verbose_json + + count_frames += cur_args['frame_num'] + + obj = threadpool_executor.submit(worker, cur_args) + objs.append(obj) + + results = [] + for obj in tqdm(objs): + result = obj.result() + results.append(result) + + log_result = {} + for ds_name in config: + if config[ds_name]['test'] == 0: + continue + log_result[ds_name] = {} + for seq in config[ds_name]['sequences']: + log_result[ds_name][seq] = {} + + for res in results: + log_result[res['ds_name']][res['seq']][f"{res['rate_idx']:03d}"] = res + + out_json_dir = os.path.dirname(args.output_path) + if len(out_json_dir) > 0: + create_folder(out_json_dir, True) + with open(args.output_path, 'w') as fp: + dump_json(log_result, fp, float_digits=6, indent=2) + + total_minutes = (time.time() - begin_time) / 60 + print('Test finished') + print(f'Tested {count_frames} frames from {count_sequences} sequences') + print(f'Total elapsed time: {total_minutes:.1f} min') + + +if __name__ == "__main__": + main() diff --git a/DCVC-family/README.md b/DCVC-family/README.md index 0565ebf..364441f 100644 --- a/DCVC-family/README.md +++ b/DCVC-family/README.md @@ -103,7 +103,7 @@ Paper (arXiv) - Code + Code Checkpoints @@ -116,6 +116,24 @@
  • The first end-to-end neural video codec achieving 100+ FPS 1080p coding and 4K real-time coding with a comparable compression ratio with ECM. + + DCVC-UF + + Paper (arXiv) + + Code + Checkpoints + + + + Propose an Ultra-Fast neural video codec with a chunk-based coding framework that eliminates explicit motion vector coding. + + + + +
  • Chunk-based framework processes multiple frames simultaneously, achieving ultra-fast encoding and decoding speeds on general-purpose GPUs that scale automatically with GPU generations. + + EVC @@ -190,6 +208,14 @@ year={2025} } +@inproceedings{li2026ultra, + title={Ultra-Fast Neural Video Compression}, + author={Li, Jiahao and Xie, Wenxuan and Jia, Zhaoyang and Li, Bin and Guo, Zongyu and Zhang, Xiaoyi and Lu, Yan}, + booktitle={{IEEE/CVF} Conference on Computer Vision and Pattern Recognition, + {CVPR} 2026, Denver, CO, USA, June 3-7, 2026}, + year={2026} +} + @inproceedings{wang2023EVC, title={EVC: Towards Real-Time Neural Image Compression with Mask Decay}, author={Wang, Guo-Hua and Li, Jiahao and Li, Bin and Lu, Yan}, diff --git a/assets/RGB_different_settings.png b/DCVC-family/assets/RGB_different_settings.png similarity index 100% rename from assets/RGB_different_settings.png rename to DCVC-family/assets/RGB_different_settings.png diff --git a/assets/test_pipeline.png b/DCVC-family/assets/test_pipeline.png similarity index 100% rename from assets/test_pipeline.png rename to DCVC-family/assets/test_pipeline.png diff --git a/test_conditions.md b/DCVC-family/test_conditions.md similarity index 100% rename from test_conditions.md rename to DCVC-family/test_conditions.md diff --git a/NOTICE .txt b/NOTICE.txt similarity index 100% rename from NOTICE .txt rename to NOTICE.txt diff --git a/README.md b/README.md index c411e62..8e0f7f2 100644 --- a/README.md +++ b/README.md @@ -1,139 +1,134 @@
    -# DCVC-RT: Towards Practical Real-Time Neural Video Compression +# DCVC-UF: Ultra-Fast Neural Video Compression -**CVPR2025** +**CVPR2026**
    -[![page](https://img.shields.io/badge/Project-Page-blue?logo=github&logoSvg)](https://dcvccodec.github.io//) -[![arXiv](https://img.shields.io/badge/arXiv-2502.20762-b31b1b.svg)](https://arxiv.org/abs/2502.20762) +[![page](https://img.shields.io/badge/Project-Page-blue?logo=github)](https://dcvccodec.github.io/) +[![arXiv](https://img.shields.io/badge/arXiv-2606.04410-b31b1b.svg)](https://arxiv.org/abs/2606.04410) -**DCVC-RT is the first neural video codec (NVC) achieving 100+ FPS 1080p coding and 4K real-time coding with a comparable compression ratio with ECM. Beyond this, DCVC-RT pursue a more practical neural video codec solution and supports various practical features, including:** -- **Wide bitrate range in single model**: A single model enables continuous and controllable bitrate adjustments. DCVC-RT can compress at a wide bitrate range for different coding scenarios. -- **Rate control**: By adjusting quantization parameters, DCVC-RT effectively supports dynamic and various network conditions during real communication scenario. -- **Unified YUV and RGB coding**: While DCVC-RT is primarily optimized for the widely adopted YUV format, it can seamlessly adapt to RGB content coding. +> [!IMPORTANT] +> # 🎉 News: training code released — see [training.md](training.md). + +**DCVC-UF is an end-to-end neural video codec (NVC) introducing a chunk-based coding framework that achieves ultra-fast encoding and decoding speeds while maintaining high compression efficiency.** + +**DCVC-UF supports various practical features, including:** +- **Wide bitrate range in single model**: A single model with 64 QP levels enables continuous and fine-grained bitrate adjustments across a wide bitrate range. +- **Rate control**: By adjusting quantization parameters, DCVC-UF effectively supports dynamic and various network conditions during real communication scenario. +- **Unified YUV and RGB coding**: While DCVC-UF is primarily optimized for the widely adopted YUV420 format, it can seamlessly adapt to RGB content coding. We are continuously exploring additional practical functionalities and will provide further NVC solutions in this repository. ## :book: Overview -Welcome to the official implementation of DCVC-RT and the broader [DCVC-family](DCVC-family/README.md) models. The DCVC (Deep Contextual Video Compression) family is designed to push the boundaries of high-performance practical neural video codecs, delivering cutting-edge compression efficiency, real-time capabilities, and versatile functionalities. +Welcome to the official implementation of DCVC-UF and the broader [DCVC-family](DCVC-family/README.md) models. The DCVC (Deep Contextual Video Compression) family is designed to push the boundaries of high-performance practical neural video codecs, delivering cutting-edge compression efficiency, ultra-fast coding speeds, and versatile functionalities. -:rocket: In this section, we provide a brief overview of DCVC-RT. For an in-depth understanding, we encourage you to read our [paper](https://arxiv.org/abs/2502.20762). +:rocket: In this section, we provide a brief overview of DCVC-UF. For an in-depth understanding, we encourage you to read our [paper](https://arxiv.org/abs/2606.04410). -:hammer: Ready to get started? Head over to the [usage](#hammer-usage) to start using this repo. +:hammer: Ready to get started? Head over to the [usage](#hammer-usage) to start using this repo. :page_facing_up: If you find our work helpful, feel free to [cite](#page_facing_up-citation) us. We truly appreciate your support. - ### Abstract -We introduce a practical real-time neural video codec (NVC) designed to deliver high compression ratio, low latency and broad versatility. In practice, the coding speed of NVCs depends on 1) computational costs, and 2) non-computational operational costs, such as memory I/O and the number of function calls. While most efficient NVCs prioritize reducing computational cost, we identify operational cost as the primary bottleneck to achieving higher coding speed. Leveraging this insight, we introduce a set of efficiency-driven design improvements focused on minimizing operational costs. Specifically, we employ implicit temporal modeling to eliminate complex explicit motion modules, and use single low-resolution latent representations rather than progressive downsampling. These innovations significantly accelerate NVC without sacrificing compression quality. Additionally, we implement model integerization for consistent cross-device coding and a module-bank-based rate control scheme to improve practical adaptability. Experiments show our proposed DCVC-RT achieves an impressive average encoding/decoding speed at 125.2/112.8 fps (frames per second) for 1080p video, while saving an average of 21\% in bitrate compared to H.266/VTM. - +While neural video codecs (NVCs) have demonstrated superior compression ratio, their prohibitive computational complexity remains a critical barrier to real-world deployment. This paper introduces a chunk-based coding framework designed to significantly improve the rate-distortion-complexity trade-off. Instead of processing frames sequentially, our approach encodes a chunk of multiple frames into a single compact latent representation and decodes them simultaneously. This is enabled by cross-frame interaction modules for joint spatial-temporal modeling and frame-specific decoders for parallel reconstruction. This paradigm not only dramatically enhances coding throughput but also facilitates more effective modeling of long-term temporal correlations. To further boost speed, we propose a streamlined entropy coding mechanism that consolidates bit-stream interactions into a single step, substantially reducing decoding overhead. Building on these innovations, we present DCVC-UF (Ultra-Fast), a new NVC that sets a new SOTA in performance. Our experiments show that DCVC-UF can achieve ultra-fast encoding and decoding speeds, significantly outperforming previous leading codecs. DCVC-UF serves as a notable landmark in the journey of NVC evolution. Both training and testing codes will be released. ### Video Compression Performance -Bit saving over VTM-17.0 (UVG all frames with single intra-frame setting (i.e. intra-period = –1) and YUV420 colorspace.) - +Bit saving over VTM-17.0 on UVG (all frames, single intra-frame setting with intra-period = -1, YUV420 colorspace). -The BD-Rate and 1080p encoding/decoding speed on NVIDIA A100 GPU + - +BD-Rate and 1080p encoding/decoding speed on NVIDIA 4090 GPU: + -The complexity analysis and encoding/decoding speed evaluation across various resolutions and devices. +Complexity analysis and encoding/decoding speed across various resolutions and devices: - ### Image Compression Performance -Notably, the intra-frame codec in DCVC-RT also delivers impressive performance. On Kodak, DCVC-RT-Intra achieves an 11.1% bitrate reduction compared to VTM, with a over 10× faster decoding speed than previous state-of-the-art learned image codecs. For encoding, DCVC-RT-Intra also offers a similar speed advantage. For 1080p content, DCVC-RT-Intra achieves an impressive encoding/decoding speed of 40.7 FPS / 44.2 FPS on an NVIDIA A100 GPU. +Notably, the intra-frame codec in DCVC-UF also delivers impressive performance. On Kodak, DCVC-UF-Intra achieves an 10.6% bitrate reduction compared to VTM, with an over 40× faster decoding speed than previous state-of-the-art learned image codecs. For encoding, DCVC-UF-Intra also offers a similar speed advantage. For 1080p content, DCVC-UF-Intra achieves an impressive encoding/decoding speed of 81.5 FPS / 95.0 FPS on an NVIDIA A100 GPU. - ## :hammer: Usage -For each step, click it to expand and view details. +Click any step below to expand its details.
    - Prerequisites
    +Prerequisites
    * Python 3.12 and conda, get [Conda](https://www.anaconda.com/) -* CUDA 12.6 (other versions may also work. Make sure the CUDA version matches with pytorch.) -* pytorch (We have tested that pytorch-2.6 works. Other versions may also work.) +* CUDA 13.0 (other versions may also work. Make sure the CUDA version matches with pytorch.) +* pytorch (We have tested that pytorch-2.9.1 works. Other versions may also work.) * Environment ``` conda create -n $YOUR_PY_ENV_NAME python=3.12 conda activate $YOUR_PY_ENV_NAME - pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126 + pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu130 pip install -r requirements.txt ```
    +Build the project
    - Build the project
    +Two C++/CUDA extensions must be built: -Please build the C++ code to support bitstream writing and customized CUDA kernels to fuse operations. +1. **MLCodec_extensions_cpp** — rANS entropy coder (pybind11) +2. **inference_extensions_cuda** — Fused inference kernels (CUTLASS-based) ```bash -sudo apt-get install cmake g++ ninja-build -conda activate $YOUR_PY_ENV_NAME -cd ./src/cpp/ -pip install . +git clone https://github.com/NVIDIA/cutlass third_party/cutlass +cd third_party/cutlass +git checkout v4.4.1 +cd ../../src/cpp/ +bash install.sh cd ../layers/extensions/inference/ -pip install . +bash install.sh ``` - -If the CUDA kernels fail to load successfully in infererence, the standard output will display: ```cannot import cuda implementation for inference, fallback to pytorch.``` -
    +CPU performance scaling
    - CPU performance scaling
    +The arithmetic coding runs on the CPU. Make sure your CPU runs at maximum frequency while encoding/decoding actual bitstreams, otherwise the entropy coding may bottleneck throughput. After each reboot, the CPU scaling governor may reset. -Note that the arithmetic coding runs on the CPU, please make sure your CPU runs at high performance while writing the actual bitstream. Otherwise, the arithmetic coding may take a long time. - -Check the CPU frequency by -``` +Check current CPU frequency: +```bash grep -E '^model name|^cpu MHz' /proc/cpuinfo ``` -Run the following command to maximum CPU frequency -``` +Set high-performance mode: +```bash echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor ``` -Run the following command to recover the default frequency -``` +Restore default: +```bash echo ondemand | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor ``` -
    +Pretrained models
    - Pretrained models
    - -* Download [our pretrained models](https://1drv.ms/f/c/2866592d5c55df8c/Esu0KJ-I2kxCjEP565ARx_YB88i0UnR6XnODqFcvZs4LcA?e=by8CO8) and put them into ./checkpoints folder. -* There are 2 models, one for image coding and the other for video coding. +* Download [our pretrained models](https://1drv.ms/f/c/2866592d5c55df8c/IgAalzb_985lQ79GkXyW2P5OASPpZHHcrcGWEVQxO-mQCVg?e=qyvMN6) and put them into `./checkpoints` folder. +* There are 4 checkpoints, one for image coding and three for video coding (HT-L, HT-S, LD variants). * As a backup, all the pretrained models could be found [here](https://1drv.ms/f/c/2866592d5c55df8c/EozfVVwtWWYggCitBAAAAAABbT4z2Z10fMXISnan72UtSA?e=BID7DA). - -
    - - Test dataset
    +Test dataset
    We support arbitrary original resolution. The input video resolution will be padded automatically. The reconstructed video will be cropped back to the original size. The distortion (PSNR) is calculated at original resolution. @@ -141,44 +136,106 @@ We support arbitrary original resolution. The input video resolution will be pad Put *.yuv in the folder structure similar to the following structure. - /media/data/HEVC_B/ - - BQTerrace_1920x1080_60.yuv - - BasketballDrive_1920x1080_50.yuv - - ... - /media/data/HEVC_D/ - /media/data/HEVC_C/ - ... +``` +/data/test_sequences/ +├── UVG/ +│ ├── Beauty_1920x1080_120fps_420_8bit_YUV.yuv +│ ├── Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv +│ └── ... +├── MCL-JCV/ +│ ├── videoSRC01_1920x1080_30.yuv +│ └── ... +└── ... +``` -The dataset structure can be seen in dataset_config_example_yuv420.json. +The dataset structure can be seen in `test_cfg/all_yuv420.json`. #### RGB content -We highly suggest testing YUV420 content. To test RGB content, please refer to the [DCVC-FM](DCVC-family/DCVC-FM) folder. +Organize PNG sequences with numbered filenames (`im00001.png`, `im00002.png`, ...). The dataset structure can be seen in `test_cfg/all_RGB.json`.
    +Test the models
    + +```bash +python test_video.py \ + --model_path_i checkpoints/cvpr2026_image.pth.tar \ + --model_path_p checkpoints/cvpr2026_video_hts.pth.tar \ + --model_structure hts \ + --rate_num 4 \ + --test_config test_cfg/all_yuv420.json \ + --output_path output.json \ + --cuda_idx 0 \ + -w 1 \ + --verbose 0 \ + --skip_thres 0.15 \ + --force_intra 0 \ + --reset_interval 128 +``` - Test the models
    +**Parameters:** +- `--model_structure {htl, hts, ld}`: Select the video model variant (HT-L, HT-S, or LD). +- `--rate_num N`: Number of rate points to test. QP values are uniformly sampled from the 64 available levels. You can also specify exact QP values with `--qp_i` and `--qp_p`. +- `--cuda_idx ID [ID ...]`: GPU device indices to use (e.g., `--cuda_idx 0 1 3`). Workers are distributed across the specified GPUs. +- `-w N`: Number of parallel workers (processes). Workers are equally spread among GPUs. +- `--verbose {0, 1, 2}`: Timing verbosity. `0` = no timing, `1` = per-sequence summary, `2` = per-frame timing. +- `--skip_thres T`: Skip threshold for adaptive entropy coding (default: 0). +- `--force_intra 1`: Test image coding only (I-frames only). + +**Output:** A JSON file with per-sequence BPP, PSNR (RGB and YUV components), MS-SSIM, and encoding/decoding timing. +
    + +
    +Measure compression speed
    -Example to test pretrained model with four rate points: ```bash - python test_video.py --model_path_i ./checkpoints/cvpr2025_image.pth.tar --model_path_p ./checkpoints/cvpr2025_video.pth.tar --rate_num 4 --test_config ./dataset_config_example_yuv420.json --cuda 1 -w 1 --write_stream 1 --force_zero_thres 0.12 --output_path output.json --force_intra_period -1 --reset_interval 64 --force_frame_num -1 --check_existing 0 --verbose 0 +python test_compress_time.py --model_structure hts ``` -It is recommended that the ```-w``` number is equal to your GPU number. +**Parameters:** +- `--model_structure {htl, hts, ld}`: Select the video model variant (HT-L, HT-S, or LD). -You can also specify different ```--rate_num``` values (2~64) to test finer bitrate adjustment. +This runs the codec on a benchmark configuration and reports average encoding/decoding time (ms/frame) and throughput (fps), accounting for chunk size. -To measure coding speed, you can set ```--verbose``` value to `1` (sequence-level measuring) or `2` (frame-level measuring). This will automatically measure encoding and decoding speeds, print them in the terminal, and record the average speeds in ```avg_frame_encoding_time``` and ```avg_frame_decoding_time``` in the output JSON file. -- Note that ```test_time``` is the total testing time for the entire sequence, which includes I/O time, encoding time, decoding time, and distortion calculation time. The overhead from I/O and distortion calculation is much larger than the encoding/decoding time itself, so we exclude these overheads to measure the precise coding time. -- Additionally, please make sure ```time.time()``` provides sufficient precision on the tested platform. For instance, our experience is that the precision is adequate on our Ubuntu device, but insufficient on our Windows device. +> **⚠️ Note:** The coding speed has been profiled and optimized for the following resolutions: 3840x2160, 1920x1080, 1280x720, 832x480, and 416x240, on the following NVIDIA GPUs: 2080Ti, 4090, A100, H100, and B200. For other resolutions and devices, the coding speed is not guaranteed to be optimal.
    +Compare models (BD-rate)
    + +First test each model with `test_video.py` and save results to JSON files. Then compare: - On the comparison
    +```bash +python compare_bd_rate.py \ + --compare_between class \ + --compare_frame_type all \ + --output_path stdout \ + --base_method VTM \ + --log_paths VTM anchors/vtm_17.0_yuv420_LB_allf_ip0.json \ + DMC-test output.json \ + --plot_rd_curve 1 \ + --plot_path test_room/figs \ + --distortion_metrics psnr +``` + +**Parameters:** +- `--compare_between {class, sequence}`: Aggregate BD-rate by class or report per-sequence. +- `--compare_frame_type {default, all}`: Frame type for BD-rate comparison. `default` compares I-frame, P-frame, and all-frame separately; `all` compares all-frame only. +- `--output_path PATH`: Output destination. Use `stdout` to print to console, or specify a `.txt`/`.csv` file path. +- `--base_method NAME`: Name of the anchor method. Must match one of the names in `--log_paths`. +- `--log_paths NAME PATH [NAME PATH ...]`: Pairs of method name and JSON result file path (e.g., `VTM anchors/vtm_17.0_yuv420_LB_allf_ip0.json DMC output.json`). The anchor VTM_17.0 results are provided under `anchors/`. +- `--plot_rd_curve {0, 1}`: Set to `1` to generate RD curve plots (default: `1`). +- `--plot_path DIR`: Directory to save the RD curve plots. +- `--distortion_metrics`: One or more of `psnr`, `msssim`, `psnr_y`, `psnr_u`, `psnr_v`, `msssim_y`, `msssim_u`, `msssim_v`. + +For more arguments, refer to `compare_bd_rate.py`. +
    + +
    +On the comparison
    Please note that different methods may use different configurations to test different models, such as * Source video may be different, e.g., cropped or padded to the desired resolution. @@ -187,14 +244,13 @@ Please note that different methods may use different configurations to test diff So, it does not make sense to compare the numbers in different methods directly, unless making sure they are using same test conditions. -Please find more details on the [test conditions](./test_conditions.md). +Please find more details on the [test conditions](DCVC-family/test_conditions.md).
    - ## :clipboard: DCVC-family -DCVC-RT builds on the success of the DCVC family of models. The details of DCVC family models can be found in [DCVC-family](DCVC-family/README.md). +DCVC-UF builds on the success of the DCVC family of models. The details of DCVC family models can be found in [DCVC-family](DCVC-family/README.md). @@ -205,17 +261,17 @@ DCVC-RT builds on the success of the DCVC family of models. The details of DCVC - - + @@ -224,7 +280,7 @@ DCVC-RT builds on the success of the DCVC family of models. The details of DCVC @@ -233,7 +289,7 @@ DCVC-RT builds on the success of the DCVC family of models. The details of DCVC @@ -242,7 +298,7 @@ DCVC-RT builds on the success of the DCVC family of models. The details of DCVC @@ -251,16 +307,25 @@ DCVC-RT builds on the success of the DCVC family of models. The details of DCVC - + + + + + + + @@ -275,7 +340,7 @@ If you find this work useful for your research, please cite:
    - BibTeX (click to expand)
    +BibTeX (click to expand)
    ``` @article{li2021deep, @@ -321,10 +386,18 @@ If you find this work useful for your research, please cite: title={Towards Practical Real-Time Neural Video Compression}, author={Jia, Zhaoyang and Li, Bin and Li, Jiahao and Xie, Wenxuan and Qi, Linfeng and Li, Houqiang and Lu, Yan}, booktitle={{IEEE/CVF} Conference on Computer Vision and Pattern Recognition, - {CVPR} 2025, Nashville, TN, USA, June 11-25, 2024}, + {CVPR} 2025, Nashville, TN, USA, June 11-15, 2025}, year={2025} } +@inproceedings{li2026ultra, + title={Ultra-Fast Neural Video Compression}, + author={Li, Jiahao and Xie, Wenxuan and Jia, Zhaoyang and Li, Bin and Guo, Zongyu and Zhang, Xiaoyi and Lu, Yan}, + booktitle={{IEEE/CVF} Conference on Computer Vision and Pattern Recognition, + {CVPR} 2026, Denver, CO, USA, June 3-7, 2026}, + year={2026} +} + @inproceedings{wang2023EVC, title={EVC: Towards Real-Time Neural Image Compression with Mask Decay}, author={Wang, Guo-Hua and Li, Jiahao and Li, Bin and Lu, Yan}, @@ -334,10 +407,9 @@ If you find this work useful for your research, please cite: ```
    - ## Acknowledgement -The implementation of DCVC-RT is based on [CompressAI](https://github.com/InterDigitalInc/CompressAI). +The implementation of DCVC-UF is based on [CompressAI](https://github.com/InterDigitalInc/CompressAI). ## Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft’s Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies. diff --git a/anchors/vtm_17.0_yuv420_LB_allf_ip0.json b/anchors/vtm_17.0_yuv420_LB_allf_ip0.json new file mode 100644 index 0000000..c86f68f --- /dev/null +++ b/anchors/vtm_17.0_yuv420_LB_allf_ip0.json @@ -0,0 +1,19200 @@ +{ + "UVG": { + "Beauty_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.057281, + "ave_i_frame_psnr": 40.086706, + "ave_i_frame_msssim": 0.982000, + "ave_i_frame_psnr_y": 39.919552, + "ave_i_frame_psnr_u": 39.437203, + "ave_i_frame_psnr_v": 41.739133, + "ave_i_frame_msssim_y": 0.982587, + "ave_i_frame_msssim_u": 0.975404, + "ave_i_frame_msssim_v": 0.985074, + "test_time": 438611.844260, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.057281, + "ave_all_frame_psnr": 40.086706, + "ave_all_frame_msssim": 0.982000, + "ave_all_frame_psnr_y": 39.919552, + "ave_all_frame_psnr_u": 39.437203, + "ave_all_frame_psnr_v": 41.739133, + "ave_all_frame_msssim_y": 0.982587, + "ave_all_frame_msssim_u": 0.975404, + "ave_all_frame_msssim_v": 0.985074, + "qp": 22, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022714, + "ave_i_frame_psnr": 39.693770, + "ave_i_frame_msssim": 0.979285, + "ave_i_frame_psnr_y": 39.458265, + "ave_i_frame_psnr_u": 39.269646, + "ave_i_frame_psnr_v": 41.530927, + "ave_i_frame_msssim_y": 0.979465, + "ave_i_frame_msssim_u": 0.973671, + "ave_i_frame_msssim_v": 0.983817, + "test_time": 270763.891115, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022714, + "ave_all_frame_psnr": 39.693770, + "ave_all_frame_msssim": 0.979285, + "ave_all_frame_psnr_y": 39.458265, + "ave_all_frame_psnr_u": 39.269646, + "ave_all_frame_psnr_v": 41.530927, + "ave_all_frame_msssim_y": 0.979465, + "ave_all_frame_msssim_u": 0.973671, + "ave_all_frame_msssim_v": 0.983817, + "qp": 25, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013001, + "ave_i_frame_psnr": 39.320024, + "ave_i_frame_msssim": 0.977011, + "ave_i_frame_psnr_y": 39.016640, + "ave_i_frame_psnr_u": 39.153528, + "ave_i_frame_psnr_v": 41.306822, + "ave_i_frame_msssim_y": 0.976867, + "ave_i_frame_msssim_u": 0.972402, + "ave_i_frame_msssim_v": 0.982485, + "test_time": 179788.829250, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013001, + "ave_all_frame_psnr": 39.320024, + "ave_all_frame_msssim": 0.977011, + "ave_all_frame_psnr_y": 39.016640, + "ave_all_frame_psnr_u": 39.153528, + "ave_all_frame_psnr_v": 41.306822, + "ave_all_frame_msssim_y": 0.976867, + "ave_all_frame_msssim_u": 0.972402, + "ave_all_frame_msssim_v": 0.982485, + "qp": 28, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007820, + "ave_i_frame_psnr": 38.831207, + "ave_i_frame_msssim": 0.973920, + "ave_i_frame_psnr_y": 38.421320, + "ave_i_frame_psnr_u": 39.042295, + "ave_i_frame_psnr_v": 41.079441, + "ave_i_frame_msssim_y": 0.973193, + "ave_i_frame_msssim_u": 0.971156, + "ave_i_frame_msssim_v": 0.981041, + "test_time": 127217.051907, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007820, + "ave_all_frame_psnr": 38.831207, + "ave_all_frame_msssim": 0.973920, + "ave_all_frame_psnr_y": 38.421320, + "ave_all_frame_psnr_u": 39.042295, + "ave_all_frame_psnr_v": 41.079441, + "ave_all_frame_msssim_y": 0.973193, + "ave_all_frame_msssim_u": 0.971156, + "ave_all_frame_msssim_v": 0.981041, + "qp": 31, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005143, + "ave_i_frame_psnr": 38.315732, + "ave_i_frame_msssim": 0.970393, + "ave_i_frame_psnr_y": 37.803007, + "ave_i_frame_psnr_u": 38.891162, + "ave_i_frame_psnr_v": 40.816651, + "ave_i_frame_msssim_y": 0.969044, + "ave_i_frame_msssim_u": 0.969534, + "ave_i_frame_msssim_v": 0.979342, + "test_time": 91702.015444, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005143, + "ave_all_frame_psnr": 38.315732, + "ave_all_frame_msssim": 0.970393, + "ave_all_frame_psnr_y": 37.803007, + "ave_all_frame_psnr_u": 38.891162, + "ave_all_frame_psnr_v": 40.816651, + "ave_all_frame_msssim_y": 0.969044, + "ave_all_frame_msssim_u": 0.969534, + "ave_all_frame_msssim_v": 0.979342, + "qp": 34, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003365, + "ave_i_frame_psnr": 37.706438, + "ave_i_frame_msssim": 0.965954, + "ave_i_frame_psnr_y": 37.047296, + "ave_i_frame_psnr_u": 38.780999, + "ave_i_frame_psnr_v": 40.586729, + "ave_i_frame_msssim_y": 0.963510, + "ave_i_frame_msssim_u": 0.968627, + "ave_i_frame_msssim_v": 0.977947, + "test_time": 66045.032996, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003365, + "ave_all_frame_psnr": 37.706438, + "ave_all_frame_msssim": 0.965954, + "ave_all_frame_psnr_y": 37.047296, + "ave_all_frame_psnr_u": 38.780999, + "ave_all_frame_psnr_v": 40.586729, + "ave_all_frame_msssim_y": 0.963510, + "ave_all_frame_msssim_u": 0.968627, + "ave_all_frame_msssim_v": 0.977947, + "qp": 37, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002191, + "ave_i_frame_psnr": 36.978862, + "ave_i_frame_msssim": 0.960141, + "ave_i_frame_psnr_y": 36.159484, + "ave_i_frame_psnr_u": 38.581721, + "ave_i_frame_psnr_v": 40.292275, + "ave_i_frame_msssim_y": 0.956351, + "ave_i_frame_msssim_u": 0.966834, + "ave_i_frame_msssim_v": 0.976194, + "test_time": 47497.379169, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002191, + "ave_all_frame_psnr": 36.978862, + "ave_all_frame_msssim": 0.960141, + "ave_all_frame_psnr_y": 36.159484, + "ave_all_frame_psnr_u": 38.581721, + "ave_all_frame_psnr_v": 40.292275, + "ave_all_frame_msssim_y": 0.956351, + "ave_all_frame_msssim_u": 0.966834, + "ave_all_frame_msssim_v": 0.976194, + "qp": 40, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001427, + "ave_i_frame_psnr": 36.139181, + "ave_i_frame_msssim": 0.952728, + "ave_i_frame_psnr_y": 35.126616, + "ave_i_frame_psnr_u": 38.409231, + "ave_i_frame_psnr_v": 39.944522, + "ave_i_frame_msssim_y": 0.947037, + "ave_i_frame_msssim_u": 0.965271, + "ave_i_frame_msssim_v": 0.974331, + "test_time": 33310.434258, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001427, + "ave_all_frame_psnr": 36.139181, + "ave_all_frame_msssim": 0.952728, + "ave_all_frame_psnr_y": 35.126616, + "ave_all_frame_psnr_u": 38.409231, + "ave_all_frame_psnr_v": 39.944522, + "ave_all_frame_msssim_y": 0.947037, + "ave_all_frame_msssim_u": 0.965271, + "ave_all_frame_msssim_v": 0.974331, + "qp": 43, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000928, + "ave_i_frame_psnr": 35.141326, + "ave_i_frame_msssim": 0.943286, + "ave_i_frame_psnr_y": 33.978637, + "ave_i_frame_psnr_u": 37.992075, + "ave_i_frame_psnr_v": 39.266710, + "ave_i_frame_msssim_y": 0.935553, + "ave_i_frame_msssim_u": 0.962229, + "ave_i_frame_msssim_v": 0.970740, + "test_time": 23984.068861, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000928, + "ave_all_frame_psnr": 35.141326, + "ave_all_frame_msssim": 0.943286, + "ave_all_frame_psnr_y": 33.978637, + "ave_all_frame_psnr_u": 37.992075, + "ave_all_frame_psnr_v": 39.266710, + "ave_all_frame_msssim_y": 0.935553, + "ave_all_frame_msssim_u": 0.962229, + "ave_all_frame_msssim_v": 0.970740, + "qp": 46, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000615, + "ave_i_frame_psnr": 34.046788, + "ave_i_frame_msssim": 0.931729, + "ave_i_frame_psnr_y": 32.744176, + "ave_i_frame_psnr_u": 37.539338, + "ave_i_frame_psnr_v": 38.369908, + "ave_i_frame_msssim_y": 0.921673, + "ave_i_frame_msssim_u": 0.958241, + "ave_i_frame_msssim_v": 0.965555, + "test_time": 16269.382057, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000615, + "ave_all_frame_psnr": 34.046788, + "ave_all_frame_msssim": 0.931729, + "ave_all_frame_psnr_y": 32.744176, + "ave_all_frame_psnr_u": 37.539338, + "ave_all_frame_psnr_v": 38.369908, + "ave_all_frame_msssim_y": 0.921673, + "ave_all_frame_msssim_u": 0.958241, + "ave_all_frame_msssim_v": 0.965555, + "qp": 49, + "ds_name": "UVG", + "seq_name": "Beauty_1920x1080_120fps_420_8bit_YUV.yuv" + } + }, + "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.044333, + "ave_i_frame_psnr": 44.561905, + "ave_i_frame_msssim": 0.993870, + "ave_i_frame_psnr_y": 43.790797, + "ave_i_frame_psnr_u": 47.158810, + "ave_i_frame_psnr_v": 46.591651, + "ave_i_frame_msssim_y": 0.993627, + "ave_i_frame_msssim_u": 0.994798, + "ave_i_frame_msssim_v": 0.994394, + "test_time": 266150.980044, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.044333, + "ave_all_frame_psnr": 44.561905, + "ave_all_frame_msssim": 0.993870, + "ave_all_frame_psnr_y": 43.790797, + "ave_all_frame_psnr_u": 47.158810, + "ave_all_frame_psnr_v": 46.591651, + "ave_all_frame_msssim_y": 0.993627, + "ave_all_frame_msssim_u": 0.994798, + "ave_all_frame_msssim_v": 0.994394, + "qp": 22, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.024321, + "ave_i_frame_psnr": 43.036859, + "ave_i_frame_msssim": 0.990817, + "ave_i_frame_psnr_y": 42.059727, + "ave_i_frame_psnr_u": 46.213671, + "ave_i_frame_psnr_v": 45.722843, + "ave_i_frame_msssim_y": 0.990108, + "ave_i_frame_msssim_u": 0.993116, + "ave_i_frame_msssim_v": 0.992770, + "test_time": 182067.617304, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.024321, + "ave_all_frame_psnr": 43.036859, + "ave_all_frame_msssim": 0.990817, + "ave_all_frame_psnr_y": 42.059727, + "ave_all_frame_psnr_u": 46.213671, + "ave_all_frame_psnr_v": 45.722843, + "ave_all_frame_msssim_y": 0.990108, + "ave_all_frame_msssim_u": 0.993116, + "ave_all_frame_msssim_v": 0.992770, + "qp": 25, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013804, + "ave_i_frame_psnr": 41.533436, + "ave_i_frame_msssim": 0.986444, + "ave_i_frame_psnr_y": 40.376552, + "ave_i_frame_psnr_u": 45.235968, + "ave_i_frame_psnr_v": 44.772203, + "ave_i_frame_msssim_y": 0.984998, + "ave_i_frame_msssim_u": 0.990917, + "ave_i_frame_msssim_v": 0.990646, + "test_time": 129394.083917, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013804, + "ave_all_frame_psnr": 41.533436, + "ave_all_frame_msssim": 0.986444, + "ave_all_frame_psnr_y": 40.376552, + "ave_all_frame_psnr_u": 45.235968, + "ave_all_frame_psnr_v": 44.772203, + "ave_all_frame_msssim_y": 0.984998, + "ave_all_frame_msssim_u": 0.990917, + "ave_all_frame_msssim_v": 0.990646, + "qp": 28, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008057, + "ave_i_frame_psnr": 40.067835, + "ave_i_frame_msssim": 0.980271, + "ave_i_frame_psnr_y": 38.748155, + "ave_i_frame_psnr_u": 44.236811, + "ave_i_frame_psnr_v": 43.816940, + "ave_i_frame_msssim_y": 0.977715, + "ave_i_frame_msssim_u": 0.988037, + "ave_i_frame_msssim_v": 0.987835, + "test_time": 97506.566211, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008057, + "ave_all_frame_psnr": 40.067835, + "ave_all_frame_msssim": 0.980271, + "ave_all_frame_psnr_y": 38.748155, + "ave_all_frame_psnr_u": 44.236811, + "ave_all_frame_psnr_v": 43.816940, + "ave_all_frame_msssim_y": 0.977715, + "ave_all_frame_msssim_u": 0.988037, + "ave_all_frame_msssim_v": 0.987835, + "qp": 31, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004983, + "ave_i_frame_psnr": 38.745696, + "ave_i_frame_msssim": 0.972426, + "ave_i_frame_psnr_y": 37.352283, + "ave_i_frame_psnr_u": 43.175558, + "ave_i_frame_psnr_v": 42.676308, + "ave_i_frame_msssim_y": 0.968575, + "ave_i_frame_msssim_u": 0.984149, + "ave_i_frame_msssim_v": 0.983812, + "test_time": 74882.323953, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004983, + "ave_all_frame_psnr": 38.745696, + "ave_all_frame_msssim": 0.972426, + "ave_all_frame_psnr_y": 37.352283, + "ave_all_frame_psnr_u": 43.175558, + "ave_all_frame_psnr_v": 42.676308, + "ave_all_frame_msssim_y": 0.968575, + "ave_all_frame_msssim_u": 0.984149, + "ave_all_frame_msssim_v": 0.983812, + "qp": 34, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003058, + "ave_i_frame_psnr": 37.546661, + "ave_i_frame_msssim": 0.962572, + "ave_i_frame_psnr_y": 35.983577, + "ave_i_frame_psnr_u": 42.526985, + "ave_i_frame_psnr_v": 41.944842, + "ave_i_frame_msssim_y": 0.956401, + "ave_i_frame_msssim_u": 0.981507, + "ave_i_frame_msssim_v": 0.980667, + "test_time": 57263.352674, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003058, + "ave_all_frame_psnr": 37.546661, + "ave_all_frame_msssim": 0.962572, + "ave_all_frame_psnr_y": 35.983577, + "ave_all_frame_psnr_u": 42.526985, + "ave_all_frame_psnr_v": 41.944842, + "ave_all_frame_msssim_y": 0.956401, + "ave_all_frame_msssim_u": 0.981507, + "ave_all_frame_msssim_v": 0.980667, + "qp": 37, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001856, + "ave_i_frame_psnr": 36.341936, + "ave_i_frame_msssim": 0.949622, + "ave_i_frame_psnr_y": 34.635590, + "ave_i_frame_psnr_u": 41.737278, + "ave_i_frame_psnr_v": 41.184665, + "ave_i_frame_msssim_y": 0.940499, + "ave_i_frame_msssim_u": 0.977306, + "ave_i_frame_msssim_v": 0.976671, + "test_time": 43326.951577, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001856, + "ave_all_frame_psnr": 36.341936, + "ave_all_frame_msssim": 0.949622, + "ave_all_frame_psnr_y": 34.635590, + "ave_all_frame_psnr_u": 41.737278, + "ave_all_frame_psnr_v": 41.184665, + "ave_all_frame_msssim_y": 0.940499, + "ave_all_frame_msssim_u": 0.977306, + "ave_all_frame_msssim_v": 0.976671, + "qp": 40, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001135, + "ave_i_frame_psnr": 35.153548, + "ave_i_frame_msssim": 0.933040, + "ave_i_frame_psnr_y": 33.299693, + "ave_i_frame_psnr_u": 40.995894, + "ave_i_frame_psnr_v": 40.434331, + "ave_i_frame_msssim_y": 0.920099, + "ave_i_frame_msssim_u": 0.972212, + "ave_i_frame_msssim_v": 0.971513, + "test_time": 32125.452603, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001135, + "ave_all_frame_psnr": 35.153548, + "ave_all_frame_msssim": 0.933040, + "ave_all_frame_psnr_y": 33.299693, + "ave_all_frame_psnr_u": 40.995894, + "ave_all_frame_psnr_v": 40.434331, + "ave_all_frame_msssim_y": 0.920099, + "ave_all_frame_msssim_u": 0.972212, + "ave_all_frame_msssim_v": 0.971513, + "qp": 43, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000693, + "ave_i_frame_psnr": 33.863117, + "ave_i_frame_msssim": 0.912036, + "ave_i_frame_psnr_y": 31.998242, + "ave_i_frame_psnr_u": 39.911031, + "ave_i_frame_psnr_v": 39.004457, + "ave_i_frame_msssim_y": 0.894846, + "ave_i_frame_msssim_u": 0.965563, + "ave_i_frame_msssim_v": 0.961650, + "test_time": 23622.866571, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000693, + "ave_all_frame_psnr": 33.863117, + "ave_all_frame_msssim": 0.912036, + "ave_all_frame_psnr_y": 31.998242, + "ave_all_frame_psnr_u": 39.911031, + "ave_all_frame_psnr_v": 39.004457, + "ave_all_frame_msssim_y": 0.894846, + "ave_all_frame_msssim_u": 0.965563, + "ave_all_frame_msssim_v": 0.961650, + "qp": 46, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000419, + "ave_i_frame_psnr": 32.551293, + "ave_i_frame_msssim": 0.884488, + "ave_i_frame_psnr_y": 30.654222, + "ave_i_frame_psnr_u": 38.644912, + "ave_i_frame_psnr_v": 37.840097, + "ave_i_frame_msssim_y": 0.861852, + "ave_i_frame_msssim_u": 0.954137, + "ave_i_frame_msssim_v": 0.950656, + "test_time": 16198.147813, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000419, + "ave_all_frame_psnr": 32.551293, + "ave_all_frame_msssim": 0.884488, + "ave_all_frame_psnr_y": 30.654222, + "ave_all_frame_psnr_u": 38.644912, + "ave_all_frame_psnr_v": 37.840097, + "ave_all_frame_msssim_y": 0.861852, + "ave_all_frame_msssim_u": 0.954137, + "ave_all_frame_msssim_v": 0.950656, + "qp": 49, + "ds_name": "UVG", + "seq_name": "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv" + } + }, + "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003187, + "ave_i_frame_psnr": 43.233234, + "ave_i_frame_msssim": 0.993934, + "ave_i_frame_psnr_y": 42.989886, + "ave_i_frame_psnr_u": 43.915272, + "ave_i_frame_psnr_v": 44.011286, + "ave_i_frame_msssim_y": 0.994235, + "ave_i_frame_msssim_u": 0.994890, + "ave_i_frame_msssim_v": 0.991173, + "test_time": 60858.543941, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003187, + "ave_all_frame_psnr": 43.233234, + "ave_all_frame_msssim": 0.993934, + "ave_all_frame_psnr_y": 42.989886, + "ave_all_frame_psnr_u": 43.915272, + "ave_all_frame_psnr_v": 44.011286, + "ave_all_frame_msssim_y": 0.994235, + "ave_all_frame_msssim_u": 0.994890, + "ave_all_frame_msssim_v": 0.991173, + "qp": 22, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001686, + "ave_i_frame_psnr": 42.597645, + "ave_i_frame_msssim": 0.992705, + "ave_i_frame_psnr_y": 42.381829, + "ave_i_frame_psnr_u": 43.003866, + "ave_i_frame_psnr_v": 43.486322, + "ave_i_frame_msssim_y": 0.993141, + "ave_i_frame_msssim_u": 0.993503, + "ave_i_frame_msssim_v": 0.989289, + "test_time": 47899.719544, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001686, + "ave_all_frame_psnr": 42.597645, + "ave_all_frame_msssim": 0.992705, + "ave_all_frame_psnr_y": 42.381829, + "ave_all_frame_psnr_u": 43.003866, + "ave_all_frame_psnr_v": 43.486322, + "ave_all_frame_msssim_y": 0.993141, + "ave_all_frame_msssim_u": 0.993503, + "ave_all_frame_msssim_v": 0.989289, + "qp": 25, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001075, + "ave_i_frame_psnr": 41.842510, + "ave_i_frame_msssim": 0.990991, + "ave_i_frame_psnr_y": 41.685394, + "ave_i_frame_psnr_u": 41.828420, + "ave_i_frame_psnr_v": 42.799298, + "ave_i_frame_msssim_y": 0.991753, + "ave_i_frame_msssim_u": 0.991083, + "ave_i_frame_msssim_v": 0.986329, + "test_time": 41913.175858, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001075, + "ave_all_frame_psnr": 41.842510, + "ave_all_frame_msssim": 0.990991, + "ave_all_frame_psnr_y": 41.685394, + "ave_all_frame_psnr_u": 41.828420, + "ave_all_frame_psnr_v": 42.799298, + "ave_all_frame_msssim_y": 0.991753, + "ave_all_frame_msssim_u": 0.991083, + "ave_all_frame_msssim_v": 0.986329, + "qp": 28, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000735, + "ave_i_frame_psnr": 40.906861, + "ave_i_frame_msssim": 0.988385, + "ave_i_frame_psnr_y": 40.816814, + "ave_i_frame_psnr_u": 40.436321, + "ave_i_frame_psnr_v": 41.917687, + "ave_i_frame_msssim_y": 0.989696, + "ave_i_frame_msssim_u": 0.987170, + "ave_i_frame_msssim_v": 0.981731, + "test_time": 34147.852821, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000735, + "ave_all_frame_psnr": 40.906861, + "ave_all_frame_msssim": 0.988385, + "ave_all_frame_psnr_y": 40.816814, + "ave_all_frame_psnr_u": 40.436321, + "ave_all_frame_psnr_v": 41.917687, + "ave_all_frame_msssim_y": 0.989696, + "ave_all_frame_msssim_u": 0.987170, + "ave_all_frame_msssim_v": 0.981731, + "qp": 31, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000534, + "ave_i_frame_psnr": 39.790311, + "ave_i_frame_msssim": 0.984430, + "ave_i_frame_psnr_y": 39.756095, + "ave_i_frame_psnr_u": 38.826088, + "ave_i_frame_psnr_v": 40.959831, + "ave_i_frame_msssim_y": 0.986552, + "ave_i_frame_msssim_u": 0.980737, + "ave_i_frame_msssim_v": 0.975389, + "test_time": 29967.783154, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000534, + "ave_all_frame_psnr": 39.790311, + "ave_all_frame_msssim": 0.984430, + "ave_all_frame_psnr_y": 39.756095, + "ave_all_frame_psnr_u": 38.826088, + "ave_all_frame_psnr_v": 40.959831, + "ave_all_frame_msssim_y": 0.986552, + "ave_all_frame_msssim_u": 0.980737, + "ave_all_frame_msssim_v": 0.975389, + "qp": 34, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000400, + "ave_i_frame_psnr": 38.528869, + "ave_i_frame_msssim": 0.978889, + "ave_i_frame_psnr_y": 38.392297, + "ave_i_frame_psnr_u": 37.701400, + "ave_i_frame_psnr_v": 40.175774, + "ave_i_frame_msssim_y": 0.981288, + "ave_i_frame_msssim_u": 0.974312, + "ave_i_frame_msssim_v": 0.969077, + "test_time": 26886.759212, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000400, + "ave_all_frame_psnr": 38.528869, + "ave_all_frame_msssim": 0.978889, + "ave_all_frame_psnr_y": 38.392297, + "ave_all_frame_psnr_u": 37.701400, + "ave_all_frame_psnr_v": 40.175774, + "ave_all_frame_msssim_y": 0.981288, + "ave_all_frame_msssim_u": 0.974312, + "ave_all_frame_msssim_v": 0.969077, + "qp": 37, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000300, + "ave_i_frame_psnr": 37.133511, + "ave_i_frame_msssim": 0.970678, + "ave_i_frame_psnr_y": 36.859105, + "ave_i_frame_psnr_u": 36.476606, + "ave_i_frame_psnr_v": 39.436850, + "ave_i_frame_msssim_y": 0.973036, + "ave_i_frame_msssim_u": 0.965476, + "ave_i_frame_msssim_v": 0.961731, + "test_time": 23661.298141, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000300, + "ave_all_frame_psnr": 37.133511, + "ave_all_frame_msssim": 0.970678, + "ave_all_frame_psnr_y": 36.859105, + "ave_all_frame_psnr_u": 36.476606, + "ave_all_frame_psnr_v": 39.436850, + "ave_all_frame_msssim_y": 0.973036, + "ave_all_frame_msssim_u": 0.965476, + "ave_all_frame_msssim_v": 0.961731, + "qp": 40, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000230, + "ave_i_frame_psnr": 35.735345, + "ave_i_frame_msssim": 0.959614, + "ave_i_frame_psnr_y": 35.199398, + "ave_i_frame_psnr_u": 35.807430, + "ave_i_frame_psnr_v": 38.878941, + "ave_i_frame_msssim_y": 0.960263, + "ave_i_frame_msssim_u": 0.959802, + "ave_i_frame_msssim_v": 0.955528, + "test_time": 19035.342465, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000230, + "ave_all_frame_psnr": 35.735345, + "ave_all_frame_msssim": 0.959614, + "ave_all_frame_psnr_y": 35.199398, + "ave_all_frame_psnr_u": 35.807430, + "ave_all_frame_psnr_v": 38.878941, + "ave_all_frame_msssim_y": 0.960263, + "ave_all_frame_msssim_u": 0.959802, + "ave_all_frame_msssim_v": 0.955528, + "qp": 43, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000173, + "ave_i_frame_psnr": 34.058698, + "ave_i_frame_msssim": 0.940351, + "ave_i_frame_psnr_y": 33.415226, + "ave_i_frame_psnr_u": 33.989708, + "ave_i_frame_psnr_v": 37.988520, + "ave_i_frame_msssim_y": 0.940007, + "ave_i_frame_msssim_u": 0.938375, + "ave_i_frame_msssim_v": 0.944390, + "test_time": 15886.931332, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000173, + "ave_all_frame_psnr": 34.058698, + "ave_all_frame_msssim": 0.940351, + "ave_all_frame_psnr_y": 33.415226, + "ave_all_frame_psnr_u": 33.989708, + "ave_all_frame_psnr_v": 37.988520, + "ave_all_frame_msssim_y": 0.940007, + "ave_all_frame_msssim_u": 0.938375, + "ave_all_frame_msssim_v": 0.944390, + "qp": 46, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000133, + "ave_i_frame_psnr": 32.394306, + "ave_i_frame_msssim": 0.914152, + "ave_i_frame_psnr_y": 31.656720, + "ave_i_frame_psnr_u": 32.214577, + "ave_i_frame_psnr_v": 36.999558, + "ave_i_frame_msssim_y": 0.912647, + "ave_i_frame_msssim_u": 0.906276, + "ave_i_frame_msssim_v": 0.931058, + "test_time": 13236.859448, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000133, + "ave_all_frame_psnr": 32.394306, + "ave_all_frame_msssim": 0.914152, + "ave_all_frame_psnr_y": 31.656720, + "ave_all_frame_psnr_u": 32.214577, + "ave_all_frame_psnr_v": 36.999558, + "ave_all_frame_msssim_y": 0.912647, + "ave_all_frame_msssim_u": 0.906276, + "ave_all_frame_msssim_v": 0.931058, + "qp": 49, + "ds_name": "UVG", + "seq_name": "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv" + } + }, + "Jockey_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.028578, + "ave_i_frame_psnr": 43.830272, + "ave_i_frame_msssim": 0.992218, + "ave_i_frame_psnr_y": 43.480176, + "ave_i_frame_psnr_u": 45.062219, + "ave_i_frame_psnr_v": 44.698898, + "ave_i_frame_msssim_y": 0.992268, + "ave_i_frame_msssim_u": 0.992226, + "ave_i_frame_msssim_v": 0.991910, + "test_time": 292571.943246, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.028578, + "ave_all_frame_psnr": 43.830272, + "ave_all_frame_msssim": 0.992218, + "ave_all_frame_psnr_y": 43.480176, + "ave_all_frame_psnr_u": 45.062219, + "ave_all_frame_psnr_v": 44.698898, + "ave_all_frame_msssim_y": 0.992268, + "ave_all_frame_msssim_u": 0.992226, + "ave_all_frame_msssim_v": 0.991910, + "qp": 22, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017535, + "ave_i_frame_psnr": 43.104404, + "ave_i_frame_msssim": 0.990280, + "ave_i_frame_psnr_y": 42.739771, + "ave_i_frame_psnr_u": 44.308173, + "ave_i_frame_psnr_v": 44.088431, + "ave_i_frame_msssim_y": 0.990342, + "ave_i_frame_msssim_u": 0.990040, + "ave_i_frame_msssim_v": 0.990149, + "test_time": 206260.539688, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017535, + "ave_all_frame_psnr": 43.104404, + "ave_all_frame_msssim": 0.990280, + "ave_all_frame_psnr_y": 42.739771, + "ave_all_frame_psnr_u": 44.308173, + "ave_all_frame_psnr_v": 44.088431, + "ave_all_frame_msssim_y": 0.990342, + "ave_all_frame_msssim_u": 0.990040, + "ave_all_frame_msssim_v": 0.990149, + "qp": 25, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011407, + "ave_i_frame_psnr": 42.212438, + "ave_i_frame_msssim": 0.987484, + "ave_i_frame_psnr_y": 41.806164, + "ave_i_frame_psnr_u": 43.484127, + "ave_i_frame_psnr_v": 43.378397, + "ave_i_frame_msssim_y": 0.987479, + "ave_i_frame_msssim_u": 0.987224, + "ave_i_frame_msssim_v": 0.987775, + "test_time": 150859.106776, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011407, + "ave_all_frame_psnr": 42.212438, + "ave_all_frame_msssim": 0.987484, + "ave_all_frame_psnr_y": 41.806164, + "ave_all_frame_psnr_u": 43.484127, + "ave_all_frame_psnr_v": 43.378397, + "ave_all_frame_msssim_y": 0.987479, + "ave_all_frame_msssim_u": 0.987224, + "ave_all_frame_msssim_v": 0.987775, + "qp": 28, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007643, + "ave_i_frame_psnr": 41.145157, + "ave_i_frame_msssim": 0.983397, + "ave_i_frame_psnr_y": 40.632330, + "ave_i_frame_psnr_u": 42.694505, + "ave_i_frame_psnr_v": 42.672767, + "ave_i_frame_msssim_y": 0.983035, + "ave_i_frame_msssim_u": 0.983975, + "ave_i_frame_msssim_v": 0.984995, + "test_time": 112005.513074, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007643, + "ave_all_frame_psnr": 41.145157, + "ave_all_frame_msssim": 0.983397, + "ave_all_frame_psnr_y": 40.632330, + "ave_all_frame_psnr_u": 42.694505, + "ave_all_frame_psnr_v": 42.672767, + "ave_all_frame_msssim_y": 0.983035, + "ave_all_frame_msssim_u": 0.983975, + "ave_all_frame_msssim_v": 0.984995, + "qp": 31, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005445, + "ave_i_frame_psnr": 40.042578, + "ave_i_frame_msssim": 0.978099, + "ave_i_frame_psnr_y": 39.448421, + "ave_i_frame_psnr_u": 41.817070, + "ave_i_frame_psnr_v": 41.833025, + "ave_i_frame_msssim_y": 0.977306, + "ave_i_frame_msssim_u": 0.979819, + "ave_i_frame_msssim_v": 0.981139, + "test_time": 83942.315719, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005445, + "ave_all_frame_psnr": 40.042578, + "ave_all_frame_msssim": 0.978099, + "ave_all_frame_psnr_y": 39.448421, + "ave_all_frame_psnr_u": 41.817070, + "ave_all_frame_psnr_v": 41.833025, + "ave_all_frame_msssim_y": 0.977306, + "ave_all_frame_msssim_u": 0.979819, + "ave_all_frame_msssim_v": 0.981139, + "qp": 34, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003932, + "ave_i_frame_psnr": 38.906940, + "ave_i_frame_msssim": 0.971291, + "ave_i_frame_psnr_y": 38.107430, + "ave_i_frame_psnr_u": 41.295123, + "ave_i_frame_psnr_v": 41.315819, + "ave_i_frame_msssim_y": 0.969086, + "ave_i_frame_msssim_u": 0.977179, + "ave_i_frame_msssim_v": 0.978632, + "test_time": 64568.927609, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003932, + "ave_all_frame_psnr": 38.906940, + "ave_all_frame_msssim": 0.971291, + "ave_all_frame_psnr_y": 38.107430, + "ave_all_frame_psnr_u": 41.295123, + "ave_all_frame_psnr_v": 41.315819, + "ave_all_frame_msssim_y": 0.969086, + "ave_all_frame_msssim_u": 0.977179, + "ave_all_frame_msssim_v": 0.978632, + "qp": 37, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002811, + "ave_i_frame_psnr": 37.619907, + "ave_i_frame_msssim": 0.961677, + "ave_i_frame_psnr_y": 36.654549, + "ave_i_frame_psnr_u": 40.516910, + "ave_i_frame_psnr_v": 40.515050, + "ave_i_frame_msssim_y": 0.957753, + "ave_i_frame_msssim_u": 0.972618, + "ave_i_frame_msssim_v": 0.974279, + "test_time": 49603.265356, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002811, + "ave_all_frame_psnr": 37.619907, + "ave_all_frame_msssim": 0.961677, + "ave_all_frame_psnr_y": 36.654549, + "ave_all_frame_psnr_u": 40.516910, + "ave_all_frame_psnr_v": 40.515050, + "ave_all_frame_msssim_y": 0.957753, + "ave_all_frame_msssim_u": 0.972618, + "ave_all_frame_msssim_v": 0.974279, + "qp": 40, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002009, + "ave_i_frame_psnr": 36.260996, + "ave_i_frame_msssim": 0.949088, + "ave_i_frame_psnr_y": 35.105742, + "ave_i_frame_psnr_u": 39.706790, + "ave_i_frame_psnr_v": 39.746724, + "ave_i_frame_msssim_y": 0.942716, + "ave_i_frame_msssim_u": 0.967590, + "ave_i_frame_msssim_v": 0.968815, + "test_time": 38296.266539, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002009, + "ave_all_frame_psnr": 36.260996, + "ave_all_frame_msssim": 0.949088, + "ave_all_frame_psnr_y": 35.105742, + "ave_all_frame_psnr_u": 39.706790, + "ave_all_frame_psnr_v": 39.746724, + "ave_all_frame_msssim_y": 0.942716, + "ave_all_frame_msssim_u": 0.967590, + "ave_all_frame_msssim_v": 0.968815, + "qp": 43, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001420, + "ave_i_frame_psnr": 34.739630, + "ave_i_frame_msssim": 0.932632, + "ave_i_frame_psnr_y": 33.508061, + "ave_i_frame_psnr_u": 38.380665, + "ave_i_frame_psnr_v": 38.488006, + "ave_i_frame_msssim_y": 0.924039, + "ave_i_frame_msssim_u": 0.957308, + "ave_i_frame_msssim_v": 0.959513, + "test_time": 27224.308535, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001420, + "ave_all_frame_psnr": 34.739630, + "ave_all_frame_msssim": 0.932632, + "ave_all_frame_psnr_y": 33.508061, + "ave_all_frame_psnr_u": 38.380665, + "ave_all_frame_psnr_v": 38.488006, + "ave_all_frame_msssim_y": 0.924039, + "ave_all_frame_msssim_u": 0.957308, + "ave_all_frame_msssim_v": 0.959513, + "qp": 46, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001005, + "ave_i_frame_psnr": 33.163176, + "ave_i_frame_msssim": 0.912214, + "ave_i_frame_psnr_y": 31.844168, + "ave_i_frame_psnr_u": 37.038032, + "ave_i_frame_psnr_v": 37.202367, + "ave_i_frame_msssim_y": 0.901175, + "ave_i_frame_msssim_u": 0.943823, + "ave_i_frame_msssim_v": 0.946840, + "test_time": 18841.668138, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001005, + "ave_all_frame_psnr": 33.163176, + "ave_all_frame_msssim": 0.912214, + "ave_all_frame_psnr_y": 31.844168, + "ave_all_frame_psnr_u": 37.038032, + "ave_all_frame_psnr_v": 37.202367, + "ave_all_frame_msssim_y": 0.901175, + "ave_all_frame_msssim_u": 0.943823, + "ave_all_frame_msssim_v": 0.946840, + "qp": 49, + "ds_name": "UVG", + "seq_name": "Jockey_1920x1080_120fps_420_8bit_YUV.yuv" + } + }, + "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.072542, + "ave_i_frame_psnr": 43.724720, + "ave_i_frame_msssim": 0.995544, + "ave_i_frame_psnr_y": 43.341213, + "ave_i_frame_psnr_u": 44.940326, + "ave_i_frame_psnr_v": 44.810158, + "ave_i_frame_msssim_y": 0.996379, + "ave_i_frame_msssim_u": 0.993361, + "ave_i_frame_msssim_v": 0.992720, + "test_time": 308837.409075, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.072542, + "ave_all_frame_psnr": 43.724720, + "ave_all_frame_msssim": 0.995544, + "ave_all_frame_psnr_y": 43.341213, + "ave_all_frame_psnr_u": 44.940326, + "ave_all_frame_psnr_v": 44.810158, + "ave_all_frame_msssim_y": 0.996379, + "ave_all_frame_msssim_u": 0.993361, + "ave_all_frame_msssim_v": 0.992720, + "qp": 22, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.047015, + "ave_i_frame_psnr": 42.038006, + "ave_i_frame_msssim": 0.993378, + "ave_i_frame_psnr_y": 41.531442, + "ave_i_frame_psnr_u": 43.547506, + "ave_i_frame_psnr_v": 43.567889, + "ave_i_frame_msssim_y": 0.994570, + "ave_i_frame_msssim_u": 0.990031, + "ave_i_frame_msssim_v": 0.989570, + "test_time": 257364.923625, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.047015, + "ave_all_frame_psnr": 42.038006, + "ave_all_frame_msssim": 0.993378, + "ave_all_frame_psnr_y": 41.531442, + "ave_all_frame_psnr_u": 43.547506, + "ave_all_frame_psnr_v": 43.567889, + "ave_all_frame_msssim_y": 0.994570, + "ave_all_frame_msssim_u": 0.990031, + "ave_all_frame_msssim_v": 0.989570, + "qp": 25, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.030816, + "ave_i_frame_psnr": 40.260797, + "ave_i_frame_msssim": 0.989971, + "ave_i_frame_psnr_y": 39.598169, + "ave_i_frame_psnr_u": 42.155960, + "ave_i_frame_psnr_v": 42.341408, + "ave_i_frame_msssim_y": 0.991557, + "ave_i_frame_msssim_u": 0.985166, + "ave_i_frame_msssim_v": 0.985262, + "test_time": 208666.427645, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.030816, + "ave_all_frame_psnr": 40.260797, + "ave_all_frame_msssim": 0.989971, + "ave_all_frame_psnr_y": 39.598169, + "ave_all_frame_psnr_u": 42.155960, + "ave_all_frame_psnr_v": 42.341408, + "ave_all_frame_msssim_y": 0.991557, + "ave_all_frame_msssim_u": 0.985166, + "ave_all_frame_msssim_v": 0.985262, + "qp": 28, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.020396, + "ave_i_frame_psnr": 38.476574, + "ave_i_frame_msssim": 0.984893, + "ave_i_frame_psnr_y": 37.600196, + "ave_i_frame_psnr_u": 40.975587, + "ave_i_frame_psnr_v": 41.235829, + "ave_i_frame_msssim_y": 0.986650, + "ave_i_frame_msssim_u": 0.979265, + "ave_i_frame_msssim_v": 0.979976, + "test_time": 168922.027035, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.020396, + "ave_all_frame_psnr": 38.476574, + "ave_all_frame_msssim": 0.984893, + "ave_all_frame_psnr_y": 37.600196, + "ave_all_frame_psnr_u": 40.975587, + "ave_all_frame_psnr_v": 41.235829, + "ave_all_frame_msssim_y": 0.986650, + "ave_all_frame_msssim_u": 0.979265, + "ave_all_frame_msssim_v": 0.979976, + "qp": 31, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014270, + "ave_i_frame_psnr": 36.848589, + "ave_i_frame_msssim": 0.977878, + "ave_i_frame_psnr_y": 35.829947, + "ave_i_frame_psnr_u": 39.696436, + "ave_i_frame_psnr_v": 40.112597, + "ave_i_frame_msssim_y": 0.979923, + "ave_i_frame_msssim_u": 0.970498, + "ave_i_frame_msssim_v": 0.972993, + "test_time": 132065.551048, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014270, + "ave_all_frame_psnr": 36.848589, + "ave_all_frame_msssim": 0.977878, + "ave_all_frame_psnr_y": 35.829947, + "ave_all_frame_psnr_u": 39.696436, + "ave_all_frame_psnr_v": 40.112597, + "ave_all_frame_msssim_y": 0.979923, + "ave_all_frame_msssim_u": 0.970498, + "ave_all_frame_msssim_v": 0.972993, + "qp": 34, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009960, + "ave_i_frame_psnr": 35.274500, + "ave_i_frame_msssim": 0.968430, + "ave_i_frame_psnr_y": 34.059505, + "ave_i_frame_psnr_u": 38.818351, + "ave_i_frame_psnr_v": 39.020623, + "ave_i_frame_msssim_y": 0.969937, + "ave_i_frame_msssim_u": 0.963278, + "ave_i_frame_msssim_v": 0.964538, + "test_time": 102094.433715, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009960, + "ave_all_frame_psnr": 35.274500, + "ave_all_frame_msssim": 0.968430, + "ave_all_frame_psnr_y": 34.059505, + "ave_all_frame_psnr_u": 38.818351, + "ave_all_frame_psnr_v": 39.020623, + "ave_all_frame_msssim_y": 0.969937, + "ave_all_frame_msssim_u": 0.963278, + "ave_all_frame_msssim_v": 0.964538, + "qp": 37, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006830, + "ave_i_frame_psnr": 33.726246, + "ave_i_frame_msssim": 0.955211, + "ave_i_frame_psnr_y": 32.292872, + "ave_i_frame_psnr_u": 37.843415, + "ave_i_frame_psnr_v": 38.209325, + "ave_i_frame_msssim_y": 0.955426, + "ave_i_frame_msssim_u": 0.952622, + "ave_i_frame_msssim_v": 0.956511, + "test_time": 77056.241518, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006830, + "ave_all_frame_psnr": 33.726246, + "ave_all_frame_msssim": 0.955211, + "ave_all_frame_psnr_y": 32.292872, + "ave_all_frame_psnr_u": 37.843415, + "ave_all_frame_psnr_v": 38.209325, + "ave_all_frame_msssim_y": 0.955426, + "ave_all_frame_msssim_u": 0.952622, + "ave_all_frame_msssim_v": 0.956511, + "qp": 40, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004636, + "ave_i_frame_psnr": 32.227062, + "ave_i_frame_msssim": 0.937483, + "ave_i_frame_psnr_y": 30.564999, + "ave_i_frame_psnr_u": 36.963541, + "ave_i_frame_psnr_v": 37.462957, + "ave_i_frame_msssim_y": 0.935296, + "ave_i_frame_msssim_u": 0.940568, + "ave_i_frame_msssim_v": 0.947520, + "test_time": 57172.589699, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004636, + "ave_all_frame_psnr": 32.227062, + "ave_all_frame_msssim": 0.937483, + "ave_all_frame_psnr_y": 30.564999, + "ave_all_frame_psnr_u": 36.963541, + "ave_all_frame_psnr_v": 37.462957, + "ave_all_frame_msssim_y": 0.935296, + "ave_all_frame_msssim_u": 0.940568, + "ave_all_frame_msssim_v": 0.947520, + "qp": 43, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003075, + "ave_i_frame_psnr": 30.662752, + "ave_i_frame_msssim": 0.912649, + "ave_i_frame_psnr_y": 28.856560, + "ave_i_frame_psnr_u": 35.733213, + "ave_i_frame_psnr_v": 36.429444, + "ave_i_frame_msssim_y": 0.908393, + "ave_i_frame_msssim_u": 0.918551, + "ave_i_frame_msssim_v": 0.932285, + "test_time": 41196.943964, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003075, + "ave_all_frame_psnr": 30.662752, + "ave_all_frame_msssim": 0.912649, + "ave_all_frame_psnr_y": 28.856560, + "ave_all_frame_psnr_u": 35.733213, + "ave_all_frame_psnr_v": 36.429444, + "ave_all_frame_msssim_y": 0.908393, + "ave_all_frame_msssim_u": 0.918551, + "ave_all_frame_msssim_v": 0.932285, + "qp": 46, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002016, + "ave_i_frame_psnr": 29.138929, + "ave_i_frame_msssim": 0.881915, + "ave_i_frame_psnr_y": 27.188525, + "ave_i_frame_psnr_u": 34.619728, + "ave_i_frame_psnr_v": 35.360557, + "ave_i_frame_msssim_y": 0.873910, + "ave_i_frame_msssim_u": 0.896803, + "ave_i_frame_msssim_v": 0.915056, + "test_time": 28517.521221, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002016, + "ave_all_frame_psnr": 29.138929, + "ave_all_frame_msssim": 0.881915, + "ave_all_frame_psnr_y": 27.188525, + "ave_all_frame_psnr_u": 34.619728, + "ave_all_frame_psnr_v": 35.360557, + "ave_all_frame_msssim_y": 0.873910, + "ave_all_frame_msssim_u": 0.896803, + "ave_all_frame_msssim_v": 0.915056, + "qp": 49, + "ds_name": "UVG", + "seq_name": "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv" + } + }, + "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.095274, + "ave_i_frame_psnr": 42.238282, + "ave_i_frame_msssim": 0.992504, + "ave_i_frame_psnr_y": 41.866167, + "ave_i_frame_psnr_u": 43.175838, + "ave_i_frame_psnr_v": 43.533417, + "ave_i_frame_msssim_y": 0.993500, + "ave_i_frame_msssim_u": 0.989993, + "ave_i_frame_msssim_v": 0.989040, + "test_time": 196144.596869, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.095274, + "ave_all_frame_psnr": 42.238282, + "ave_all_frame_msssim": 0.992504, + "ave_all_frame_psnr_y": 41.866167, + "ave_all_frame_psnr_u": 43.175838, + "ave_all_frame_psnr_v": 43.533417, + "ave_all_frame_msssim_y": 0.993500, + "ave_all_frame_msssim_u": 0.989993, + "ave_all_frame_msssim_v": 0.989040, + "qp": 22, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.055177, + "ave_i_frame_psnr": 40.923664, + "ave_i_frame_msssim": 0.988866, + "ave_i_frame_psnr_y": 40.375098, + "ave_i_frame_psnr_u": 42.330628, + "ave_i_frame_psnr_v": 42.808094, + "ave_i_frame_msssim_y": 0.989720, + "ave_i_frame_msssim_u": 0.986644, + "ave_i_frame_msssim_v": 0.985967, + "test_time": 143256.435279, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.055177, + "ave_all_frame_psnr": 40.923664, + "ave_all_frame_msssim": 0.988866, + "ave_all_frame_psnr_y": 40.375098, + "ave_all_frame_psnr_u": 42.330628, + "ave_all_frame_psnr_v": 42.808094, + "ave_all_frame_msssim_y": 0.989720, + "ave_all_frame_msssim_u": 0.986644, + "ave_all_frame_msssim_v": 0.985967, + "qp": 25, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.030000, + "ave_i_frame_psnr": 39.508879, + "ave_i_frame_msssim": 0.982981, + "ave_i_frame_psnr_y": 38.761485, + "ave_i_frame_psnr_u": 41.408261, + "ave_i_frame_psnr_v": 42.093863, + "ave_i_frame_msssim_y": 0.983261, + "ave_i_frame_msssim_u": 0.982030, + "ave_i_frame_msssim_v": 0.982251, + "test_time": 103044.416312, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.030000, + "ave_all_frame_psnr": 39.508879, + "ave_all_frame_msssim": 0.982981, + "ave_all_frame_psnr_y": 38.761485, + "ave_all_frame_psnr_u": 41.408261, + "ave_all_frame_psnr_v": 42.093863, + "ave_all_frame_msssim_y": 0.983261, + "ave_all_frame_msssim_u": 0.982030, + "ave_all_frame_msssim_v": 0.982251, + "qp": 28, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014959, + "ave_i_frame_psnr": 38.053151, + "ave_i_frame_msssim": 0.973773, + "ave_i_frame_psnr_y": 37.089855, + "ave_i_frame_psnr_u": 40.479419, + "ave_i_frame_psnr_v": 41.406664, + "ave_i_frame_msssim_y": 0.972662, + "ave_i_frame_msssim_u": 0.976112, + "ave_i_frame_msssim_v": 0.978096, + "test_time": 70830.962078, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014959, + "ave_all_frame_psnr": 38.053151, + "ave_all_frame_msssim": 0.973773, + "ave_all_frame_psnr_y": 37.089855, + "ave_all_frame_psnr_u": 40.479419, + "ave_all_frame_psnr_v": 41.406664, + "ave_all_frame_msssim_y": 0.972662, + "ave_all_frame_msssim_u": 0.976112, + "ave_all_frame_msssim_v": 0.978096, + "qp": 31, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007790, + "ave_i_frame_psnr": 36.738817, + "ave_i_frame_msssim": 0.962677, + "ave_i_frame_psnr_y": 35.610734, + "ave_i_frame_psnr_u": 39.541931, + "ave_i_frame_psnr_v": 40.704202, + "ave_i_frame_msssim_y": 0.959969, + "ave_i_frame_msssim_u": 0.968609, + "ave_i_frame_msssim_v": 0.972995, + "test_time": 46245.194756, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007790, + "ave_all_frame_psnr": 36.738817, + "ave_all_frame_msssim": 0.962677, + "ave_all_frame_psnr_y": 35.610734, + "ave_all_frame_psnr_u": 39.541931, + "ave_all_frame_psnr_v": 40.704202, + "ave_all_frame_msssim_y": 0.959969, + "ave_all_frame_msssim_u": 0.968609, + "ave_all_frame_msssim_v": 0.972995, + "qp": 34, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003909, + "ave_i_frame_psnr": 35.490419, + "ave_i_frame_msssim": 0.949432, + "ave_i_frame_psnr_y": 34.147938, + "ave_i_frame_psnr_u": 38.913287, + "ave_i_frame_psnr_v": 40.122435, + "ave_i_frame_msssim_y": 0.944080, + "ave_i_frame_msssim_u": 0.962970, + "ave_i_frame_msssim_v": 0.968007, + "test_time": 30737.890053, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003909, + "ave_all_frame_psnr": 35.490419, + "ave_all_frame_msssim": 0.949432, + "ave_all_frame_psnr_y": 34.147938, + "ave_all_frame_psnr_u": 38.913287, + "ave_all_frame_psnr_v": 40.122435, + "ave_all_frame_msssim_y": 0.944080, + "ave_all_frame_msssim_u": 0.962970, + "ave_all_frame_msssim_v": 0.968007, + "qp": 37, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002080, + "ave_i_frame_psnr": 34.252598, + "ave_i_frame_msssim": 0.933414, + "ave_i_frame_psnr_y": 32.703531, + "ave_i_frame_psnr_u": 38.151093, + "ave_i_frame_psnr_v": 39.648507, + "ave_i_frame_msssim_y": 0.924914, + "ave_i_frame_msssim_u": 0.954170, + "ave_i_frame_msssim_v": 0.963663, + "test_time": 21904.302719, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002080, + "ave_all_frame_psnr": 34.252598, + "ave_all_frame_msssim": 0.933414, + "ave_all_frame_psnr_y": 32.703531, + "ave_all_frame_psnr_u": 38.151093, + "ave_all_frame_psnr_v": 39.648507, + "ave_all_frame_msssim_y": 0.924914, + "ave_all_frame_msssim_u": 0.954170, + "ave_all_frame_msssim_v": 0.963663, + "qp": 40, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001167, + "ave_i_frame_psnr": 33.024525, + "ave_i_frame_msssim": 0.911573, + "ave_i_frame_psnr_y": 31.234913, + "ave_i_frame_psnr_u": 37.596806, + "ave_i_frame_psnr_v": 39.189913, + "ave_i_frame_msssim_y": 0.897663, + "ave_i_frame_msssim_u": 0.947462, + "ave_i_frame_msssim_v": 0.959147, + "test_time": 16027.443484, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001167, + "ave_all_frame_psnr": 33.024525, + "ave_all_frame_msssim": 0.911573, + "ave_all_frame_psnr_y": 31.234913, + "ave_all_frame_psnr_u": 37.596806, + "ave_all_frame_psnr_v": 39.189913, + "ave_all_frame_msssim_y": 0.897663, + "ave_all_frame_msssim_u": 0.947462, + "ave_all_frame_msssim_v": 0.959147, + "qp": 43, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000698, + "ave_i_frame_psnr": 31.750718, + "ave_i_frame_msssim": 0.881326, + "ave_i_frame_psnr_y": 29.791464, + "ave_i_frame_psnr_u": 36.681559, + "ave_i_frame_psnr_v": 38.575402, + "ave_i_frame_msssim_y": 0.860607, + "ave_i_frame_msssim_u": 0.934568, + "ave_i_frame_msssim_v": 0.952398, + "test_time": 12358.642844, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000698, + "ave_all_frame_psnr": 31.750718, + "ave_all_frame_msssim": 0.881326, + "ave_all_frame_psnr_y": 29.791464, + "ave_all_frame_psnr_u": 36.681559, + "ave_all_frame_psnr_v": 38.575402, + "ave_all_frame_msssim_y": 0.860607, + "ave_all_frame_msssim_u": 0.934568, + "ave_all_frame_msssim_v": 0.952398, + "qp": 46, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000441, + "ave_i_frame_psnr": 30.442924, + "ave_i_frame_msssim": 0.841444, + "ave_i_frame_psnr_y": 28.351065, + "ave_i_frame_psnr_u": 35.607173, + "ave_i_frame_psnr_v": 37.829826, + "ave_i_frame_msssim_y": 0.811564, + "ave_i_frame_msssim_u": 0.917760, + "ave_i_frame_msssim_v": 0.944410, + "test_time": 9674.430823, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000441, + "ave_all_frame_psnr": 30.442924, + "ave_all_frame_msssim": 0.841444, + "ave_all_frame_psnr_y": 28.351065, + "ave_all_frame_psnr_u": 35.607173, + "ave_all_frame_psnr_v": 37.829826, + "ave_all_frame_msssim_y": 0.811564, + "ave_all_frame_msssim_u": 0.917760, + "ave_all_frame_msssim_v": 0.944410, + "qp": 49, + "ds_name": "UVG", + "seq_name": "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv" + } + }, + "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.160136, + "ave_i_frame_psnr": 43.499274, + "ave_i_frame_msssim": 0.993598, + "ave_i_frame_psnr_y": 42.882569, + "ave_i_frame_psnr_u": 45.891546, + "ave_i_frame_psnr_v": 44.807234, + "ave_i_frame_msssim_y": 0.993840, + "ave_i_frame_msssim_u": 0.993463, + "ave_i_frame_msssim_v": 0.992284, + "test_time": 409898.952615, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.160136, + "ave_all_frame_psnr": 43.499274, + "ave_all_frame_msssim": 0.993598, + "ave_all_frame_psnr_y": 42.882569, + "ave_all_frame_psnr_u": 45.891546, + "ave_all_frame_psnr_v": 44.807234, + "ave_all_frame_msssim_y": 0.993840, + "ave_all_frame_msssim_u": 0.993463, + "ave_all_frame_msssim_v": 0.992284, + "qp": 22, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.098683, + "ave_i_frame_psnr": 41.472721, + "ave_i_frame_msssim": 0.989425, + "ave_i_frame_psnr_y": 40.590103, + "ave_i_frame_psnr_u": 44.668099, + "ave_i_frame_psnr_v": 43.573050, + "ave_i_frame_msssim_y": 0.989262, + "ave_i_frame_msssim_u": 0.990680, + "ave_i_frame_msssim_v": 0.989152, + "test_time": 361984.190774, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.098683, + "ave_all_frame_psnr": 41.472721, + "ave_all_frame_msssim": 0.989425, + "ave_all_frame_psnr_y": 40.590103, + "ave_all_frame_psnr_u": 44.668099, + "ave_all_frame_psnr_v": 43.573050, + "ave_all_frame_msssim_y": 0.989262, + "ave_all_frame_msssim_u": 0.990680, + "ave_all_frame_msssim_v": 0.989152, + "qp": 25, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.059039, + "ave_i_frame_psnr": 39.458400, + "ave_i_frame_msssim": 0.982717, + "ave_i_frame_psnr_y": 38.283444, + "ave_i_frame_psnr_u": 43.540757, + "ave_i_frame_psnr_v": 42.425777, + "ave_i_frame_msssim_y": 0.981528, + "ave_i_frame_msssim_u": 0.987277, + "ave_i_frame_msssim_v": 0.985288, + "test_time": 284303.811971, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.059039, + "ave_all_frame_psnr": 39.458400, + "ave_all_frame_msssim": 0.982717, + "ave_all_frame_psnr_y": 38.283444, + "ave_all_frame_psnr_u": 43.540757, + "ave_all_frame_psnr_v": 42.425777, + "ave_all_frame_msssim_y": 0.981528, + "ave_all_frame_msssim_u": 0.987277, + "ave_all_frame_msssim_v": 0.985288, + "qp": 28, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.034248, + "ave_i_frame_psnr": 37.549551, + "ave_i_frame_msssim": 0.972724, + "ave_i_frame_psnr_y": 36.057727, + "ave_i_frame_psnr_u": 42.585083, + "ave_i_frame_psnr_v": 41.464962, + "ave_i_frame_msssim_y": 0.969451, + "ave_i_frame_msssim_u": 0.983738, + "ave_i_frame_msssim_v": 0.981348, + "test_time": 210332.182393, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.034248, + "ave_all_frame_psnr": 37.549551, + "ave_all_frame_msssim": 0.972724, + "ave_all_frame_psnr_y": 36.057727, + "ave_all_frame_psnr_u": 42.585083, + "ave_all_frame_psnr_v": 41.464962, + "ave_all_frame_msssim_y": 0.969451, + "ave_all_frame_msssim_u": 0.983738, + "ave_all_frame_msssim_v": 0.981348, + "qp": 31, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.021074, + "ave_i_frame_psnr": 36.024665, + "ave_i_frame_msssim": 0.961072, + "ave_i_frame_psnr_y": 34.356227, + "ave_i_frame_psnr_u": 41.586906, + "ave_i_frame_psnr_v": 40.473052, + "ave_i_frame_msssim_y": 0.955572, + "ave_i_frame_msssim_u": 0.978983, + "ave_i_frame_msssim_v": 0.976168, + "test_time": 161458.052346, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.021074, + "ave_all_frame_psnr": 36.024665, + "ave_all_frame_msssim": 0.961072, + "ave_all_frame_psnr_y": 34.356227, + "ave_all_frame_psnr_u": 41.586906, + "ave_all_frame_psnr_v": 40.473052, + "ave_all_frame_msssim_y": 0.955572, + "ave_all_frame_msssim_u": 0.978983, + "ave_all_frame_msssim_v": 0.976168, + "qp": 34, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012579, + "ave_i_frame_psnr": 34.669880, + "ave_i_frame_msssim": 0.946460, + "ave_i_frame_psnr_y": 32.755244, + "ave_i_frame_psnr_u": 41.017060, + "ave_i_frame_psnr_v": 39.810513, + "ave_i_frame_msssim_y": 0.937241, + "ave_i_frame_msssim_u": 0.975942, + "ave_i_frame_msssim_v": 0.972294, + "test_time": 116763.319219, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012579, + "ave_all_frame_psnr": 34.669880, + "ave_all_frame_msssim": 0.946460, + "ave_all_frame_psnr_y": 32.755244, + "ave_all_frame_psnr_u": 41.017060, + "ave_all_frame_psnr_v": 39.810513, + "ave_all_frame_msssim_y": 0.937241, + "ave_all_frame_msssim_u": 0.975942, + "ave_all_frame_msssim_v": 0.972294, + "qp": 37, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007236, + "ave_i_frame_psnr": 33.403288, + "ave_i_frame_msssim": 0.928191, + "ave_i_frame_psnr_y": 31.280699, + "ave_i_frame_psnr_u": 40.400614, + "ave_i_frame_psnr_v": 39.141493, + "ave_i_frame_msssim_y": 0.914320, + "ave_i_frame_msssim_u": 0.972046, + "ave_i_frame_msssim_v": 0.967566, + "test_time": 81357.452781, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007236, + "ave_all_frame_psnr": 33.403288, + "ave_all_frame_msssim": 0.928191, + "ave_all_frame_psnr_y": 31.280699, + "ave_all_frame_psnr_u": 40.400614, + "ave_all_frame_psnr_v": 39.141493, + "ave_all_frame_msssim_y": 0.914320, + "ave_all_frame_msssim_u": 0.972046, + "ave_all_frame_msssim_v": 0.967566, + "qp": 40, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004076, + "ave_i_frame_psnr": 32.257202, + "ave_i_frame_msssim": 0.906868, + "ave_i_frame_psnr_y": 29.952961, + "ave_i_frame_psnr_u": 39.818229, + "ave_i_frame_psnr_v": 38.521619, + "ave_i_frame_msssim_y": 0.887283, + "ave_i_frame_msssim_u": 0.968155, + "ave_i_frame_msssim_v": 0.963090, + "test_time": 56627.106617, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004076, + "ave_all_frame_psnr": 32.257202, + "ave_all_frame_msssim": 0.906868, + "ave_all_frame_psnr_y": 29.952961, + "ave_all_frame_psnr_u": 39.818229, + "ave_all_frame_psnr_v": 38.521619, + "ave_all_frame_msssim_y": 0.887283, + "ave_all_frame_msssim_u": 0.968155, + "ave_all_frame_msssim_v": 0.963090, + "qp": 43, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002234, + "ave_i_frame_psnr": 31.104927, + "ave_i_frame_msssim": 0.882020, + "ave_i_frame_psnr_y": 28.743504, + "ave_i_frame_psnr_u": 38.820797, + "ave_i_frame_psnr_v": 37.557593, + "ave_i_frame_msssim_y": 0.856963, + "ave_i_frame_msssim_u": 0.960177, + "ave_i_frame_msssim_v": 0.954207, + "test_time": 37161.943574, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002234, + "ave_all_frame_psnr": 31.104927, + "ave_all_frame_msssim": 0.882020, + "ave_all_frame_psnr_y": 28.743504, + "ave_all_frame_psnr_u": 38.820797, + "ave_all_frame_psnr_v": 37.557593, + "ave_all_frame_msssim_y": 0.856963, + "ave_all_frame_msssim_u": 0.960177, + "ave_all_frame_msssim_v": 0.954207, + "qp": 46, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001221, + "ave_i_frame_psnr": 30.069787, + "ave_i_frame_msssim": 0.855415, + "ave_i_frame_psnr_y": 27.637635, + "ave_i_frame_psnr_u": 38.131863, + "ave_i_frame_psnr_v": 36.600627, + "ave_i_frame_msssim_y": 0.824222, + "ave_i_frame_msssim_u": 0.953165, + "ave_i_frame_msssim_v": 0.944827, + "test_time": 23759.117367, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001221, + "ave_all_frame_psnr": 30.069787, + "ave_all_frame_msssim": 0.855415, + "ave_all_frame_psnr_y": 27.637635, + "ave_all_frame_psnr_u": 38.131863, + "ave_all_frame_psnr_v": 36.600627, + "ave_all_frame_msssim_y": 0.824222, + "ave_all_frame_msssim_u": 0.953165, + "ave_all_frame_msssim_v": 0.944827, + "qp": 49, + "ds_name": "UVG", + "seq_name": "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv" + } + } + }, + "MCL-JCV": { + "videoSRC01_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008460, + "ave_i_frame_psnr": 43.627400, + "ave_i_frame_msssim": 0.991955, + "ave_i_frame_psnr_y": 42.736563, + "ave_i_frame_psnr_u": 46.915014, + "ave_i_frame_psnr_v": 45.684806, + "ave_i_frame_msssim_y": 0.991549, + "ave_i_frame_msssim_u": 0.993962, + "ave_i_frame_msssim_v": 0.992386, + "test_time": 25400.664351, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008460, + "ave_all_frame_psnr": 43.627400, + "ave_all_frame_msssim": 0.991955, + "ave_all_frame_psnr_y": 42.736563, + "ave_all_frame_psnr_u": 46.915014, + "ave_all_frame_psnr_v": 45.684806, + "ave_all_frame_msssim_y": 0.991549, + "ave_all_frame_msssim_u": 0.993962, + "ave_all_frame_msssim_v": 0.992386, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004215, + "ave_i_frame_psnr": 43.232429, + "ave_i_frame_msssim": 0.990893, + "ave_i_frame_psnr_y": 42.290219, + "ave_i_frame_psnr_u": 46.637488, + "ave_i_frame_psnr_v": 45.480630, + "ave_i_frame_msssim_y": 0.990333, + "ave_i_frame_msssim_u": 0.993336, + "ave_i_frame_msssim_v": 0.991805, + "test_time": 17039.527409, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004215, + "ave_all_frame_psnr": 43.232429, + "ave_all_frame_msssim": 0.990893, + "ave_all_frame_psnr_y": 42.290219, + "ave_all_frame_psnr_u": 46.637488, + "ave_all_frame_psnr_v": 45.480630, + "ave_all_frame_msssim_y": 0.990333, + "ave_all_frame_msssim_u": 0.993336, + "ave_all_frame_msssim_v": 0.991805, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002511, + "ave_i_frame_psnr": 42.758909, + "ave_i_frame_msssim": 0.989471, + "ave_i_frame_psnr_y": 41.756416, + "ave_i_frame_psnr_u": 46.297959, + "ave_i_frame_psnr_v": 45.234816, + "ave_i_frame_msssim_y": 0.988685, + "ave_i_frame_msssim_u": 0.992554, + "ave_i_frame_msssim_v": 0.991102, + "test_time": 13340.014154, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002511, + "ave_all_frame_psnr": 42.758909, + "ave_all_frame_msssim": 0.989471, + "ave_all_frame_psnr_y": 41.756416, + "ave_all_frame_psnr_u": 46.297959, + "ave_all_frame_psnr_v": 45.234816, + "ave_all_frame_msssim_y": 0.988685, + "ave_all_frame_msssim_u": 0.992554, + "ave_all_frame_msssim_v": 0.991102, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001563, + "ave_i_frame_psnr": 42.168728, + "ave_i_frame_msssim": 0.987458, + "ave_i_frame_psnr_y": 41.113169, + "ave_i_frame_psnr_u": 45.794625, + "ave_i_frame_psnr_v": 44.876180, + "ave_i_frame_msssim_y": 0.986397, + "ave_i_frame_msssim_u": 0.991236, + "ave_i_frame_msssim_v": 0.990051, + "test_time": 9926.350919, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001563, + "ave_all_frame_psnr": 42.168728, + "ave_all_frame_msssim": 0.987458, + "ave_all_frame_psnr_y": 41.113169, + "ave_all_frame_psnr_u": 45.794625, + "ave_all_frame_psnr_v": 44.876180, + "ave_all_frame_msssim_y": 0.986397, + "ave_all_frame_msssim_u": 0.991236, + "ave_all_frame_msssim_v": 0.990051, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001046, + "ave_i_frame_psnr": 41.474184, + "ave_i_frame_msssim": 0.984579, + "ave_i_frame_psnr_y": 40.351672, + "ave_i_frame_psnr_u": 45.195257, + "ave_i_frame_psnr_v": 44.488181, + "ave_i_frame_msssim_y": 0.983023, + "ave_i_frame_msssim_u": 0.989649, + "ave_i_frame_msssim_v": 0.988840, + "test_time": 8019.964020, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001046, + "ave_all_frame_psnr": 41.474184, + "ave_all_frame_msssim": 0.984579, + "ave_all_frame_psnr_y": 40.351672, + "ave_all_frame_psnr_u": 45.195257, + "ave_all_frame_psnr_v": 44.488181, + "ave_all_frame_msssim_y": 0.983023, + "ave_all_frame_msssim_u": 0.989649, + "ave_all_frame_msssim_v": 0.988840, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000690, + "ave_i_frame_psnr": 40.745061, + "ave_i_frame_msssim": 0.981017, + "ave_i_frame_psnr_y": 39.500545, + "ave_i_frame_psnr_u": 44.845554, + "ave_i_frame_psnr_v": 44.111665, + "ave_i_frame_msssim_y": 0.978678, + "ave_i_frame_msssim_u": 0.988454, + "ave_i_frame_msssim_v": 0.987619, + "test_time": 6354.296414, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000690, + "ave_all_frame_psnr": 40.745061, + "ave_all_frame_msssim": 0.981017, + "ave_all_frame_psnr_y": 39.500545, + "ave_all_frame_psnr_u": 44.845554, + "ave_all_frame_psnr_v": 44.111665, + "ave_all_frame_msssim_y": 0.978678, + "ave_all_frame_msssim_u": 0.988454, + "ave_all_frame_msssim_v": 0.987619, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000465, + "ave_i_frame_psnr": 39.900199, + "ave_i_frame_msssim": 0.976087, + "ave_i_frame_psnr_y": 38.512013, + "ave_i_frame_psnr_u": 44.266360, + "ave_i_frame_psnr_v": 43.863153, + "ave_i_frame_msssim_y": 0.972614, + "ave_i_frame_msssim_u": 0.986422, + "ave_i_frame_msssim_v": 0.986589, + "test_time": 4854.206061, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000465, + "ave_all_frame_psnr": 39.900199, + "ave_all_frame_msssim": 0.976087, + "ave_all_frame_psnr_y": 38.512013, + "ave_all_frame_psnr_u": 44.266360, + "ave_all_frame_psnr_v": 43.863153, + "ave_all_frame_msssim_y": 0.972614, + "ave_all_frame_msssim_u": 0.986422, + "ave_all_frame_msssim_v": 0.986589, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000320, + "ave_i_frame_psnr": 38.958657, + "ave_i_frame_msssim": 0.969657, + "ave_i_frame_psnr_y": 37.402759, + "ave_i_frame_psnr_u": 43.755229, + "ave_i_frame_psnr_v": 43.497475, + "ave_i_frame_msssim_y": 0.964585, + "ave_i_frame_msssim_u": 0.984641, + "ave_i_frame_msssim_v": 0.985101, + "test_time": 3968.099341, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000320, + "ave_all_frame_psnr": 38.958657, + "ave_all_frame_msssim": 0.969657, + "ave_all_frame_psnr_y": 37.402759, + "ave_all_frame_psnr_u": 43.755229, + "ave_all_frame_psnr_v": 43.497475, + "ave_all_frame_msssim_y": 0.964585, + "ave_all_frame_msssim_u": 0.984641, + "ave_all_frame_msssim_v": 0.985101, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000229, + "ave_i_frame_psnr": 37.846999, + "ave_i_frame_msssim": 0.961455, + "ave_i_frame_psnr_y": 36.216936, + "ave_i_frame_psnr_u": 42.847373, + "ave_i_frame_psnr_v": 42.626997, + "ave_i_frame_msssim_y": 0.954612, + "ave_i_frame_msssim_u": 0.981892, + "ave_i_frame_msssim_v": 0.982072, + "test_time": 3549.350854, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000229, + "ave_all_frame_psnr": 37.846999, + "ave_all_frame_msssim": 0.961455, + "ave_all_frame_psnr_y": 36.216936, + "ave_all_frame_psnr_u": 42.847373, + "ave_all_frame_psnr_v": 42.626997, + "ave_all_frame_msssim_y": 0.954612, + "ave_all_frame_msssim_u": 0.981892, + "ave_all_frame_msssim_v": 0.982072, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000177, + "ave_i_frame_psnr": 36.638550, + "ave_i_frame_msssim": 0.951263, + "ave_i_frame_psnr_y": 34.955273, + "ave_i_frame_psnr_u": 41.987841, + "ave_i_frame_psnr_v": 41.388922, + "ave_i_frame_msssim_y": 0.942301, + "ave_i_frame_msssim_u": 0.978340, + "ave_i_frame_msssim_v": 0.977961, + "test_time": 3262.492706, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000177, + "ave_all_frame_psnr": 36.638550, + "ave_all_frame_msssim": 0.951263, + "ave_all_frame_psnr_y": 34.955273, + "ave_all_frame_psnr_u": 41.987841, + "ave_all_frame_psnr_v": 41.388922, + "ave_all_frame_msssim_y": 0.942301, + "ave_all_frame_msssim_u": 0.978340, + "ave_all_frame_msssim_v": 0.977961, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC01_1920x1080_30.yuv" + } + }, + "videoSRC02_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.036296, + "ave_i_frame_psnr": 46.971288, + "ave_i_frame_msssim": 0.996276, + "ave_i_frame_psnr_y": 46.261392, + "ave_i_frame_psnr_u": 48.586360, + "ave_i_frame_psnr_v": 49.615590, + "ave_i_frame_msssim_y": 0.996379, + "ave_i_frame_msssim_u": 0.995538, + "ave_i_frame_msssim_v": 0.996399, + "test_time": 66715.529829, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.036296, + "ave_all_frame_psnr": 46.971288, + "ave_all_frame_msssim": 0.996276, + "ave_all_frame_psnr_y": 46.261392, + "ave_all_frame_psnr_u": 48.586360, + "ave_all_frame_psnr_v": 49.615590, + "ave_all_frame_msssim_y": 0.996379, + "ave_all_frame_msssim_u": 0.995538, + "ave_all_frame_msssim_v": 0.996399, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.024355, + "ave_i_frame_psnr": 45.602952, + "ave_i_frame_msssim": 0.994561, + "ave_i_frame_psnr_y": 44.832364, + "ave_i_frame_psnr_u": 47.441260, + "ave_i_frame_psnr_v": 48.388170, + "ave_i_frame_msssim_y": 0.994639, + "ave_i_frame_msssim_u": 0.993743, + "ave_i_frame_msssim_v": 0.994909, + "test_time": 52770.676486, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.024355, + "ave_all_frame_psnr": 45.602952, + "ave_all_frame_msssim": 0.994561, + "ave_all_frame_psnr_y": 44.832364, + "ave_all_frame_psnr_u": 47.441260, + "ave_all_frame_psnr_v": 48.388170, + "ave_all_frame_msssim_y": 0.994639, + "ave_all_frame_msssim_u": 0.993743, + "ave_all_frame_msssim_v": 0.994909, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016548, + "ave_i_frame_psnr": 44.054754, + "ave_i_frame_msssim": 0.991987, + "ave_i_frame_psnr_y": 43.182274, + "ave_i_frame_psnr_u": 46.215609, + "ave_i_frame_psnr_v": 47.128778, + "ave_i_frame_msssim_y": 0.991951, + "ave_i_frame_msssim_u": 0.991290, + "ave_i_frame_msssim_v": 0.992897, + "test_time": 41069.117006, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016548, + "ave_all_frame_psnr": 44.054754, + "ave_all_frame_msssim": 0.991987, + "ave_all_frame_psnr_y": 43.182274, + "ave_all_frame_psnr_u": 46.215609, + "ave_all_frame_psnr_v": 47.128778, + "ave_all_frame_msssim_y": 0.991951, + "ave_all_frame_msssim_u": 0.991290, + "ave_all_frame_msssim_v": 0.992897, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011366, + "ave_i_frame_psnr": 42.386832, + "ave_i_frame_msssim": 0.988266, + "ave_i_frame_psnr_y": 41.335942, + "ave_i_frame_psnr_u": 45.114639, + "ave_i_frame_psnr_v": 45.964366, + "ave_i_frame_msssim_y": 0.987872, + "ave_i_frame_msssim_u": 0.988405, + "ave_i_frame_msssim_v": 0.990489, + "test_time": 31274.186900, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011366, + "ave_all_frame_psnr": 42.386832, + "ave_all_frame_msssim": 0.988266, + "ave_all_frame_psnr_y": 41.335942, + "ave_all_frame_psnr_u": 45.114639, + "ave_all_frame_psnr_v": 45.964366, + "ave_all_frame_msssim_y": 0.987872, + "ave_all_frame_msssim_u": 0.988405, + "ave_all_frame_msssim_v": 0.990489, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008269, + "ave_i_frame_psnr": 40.850195, + "ave_i_frame_msssim": 0.983489, + "ave_i_frame_psnr_y": 39.693703, + "ave_i_frame_psnr_u": 43.948162, + "ave_i_frame_psnr_v": 44.691175, + "ave_i_frame_msssim_y": 0.982760, + "ave_i_frame_msssim_u": 0.984277, + "ave_i_frame_msssim_v": 0.987070, + "test_time": 24507.563439, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008269, + "ave_all_frame_psnr": 40.850195, + "ave_all_frame_msssim": 0.983489, + "ave_all_frame_psnr_y": 39.693703, + "ave_all_frame_psnr_u": 43.948162, + "ave_all_frame_psnr_v": 44.691175, + "ave_all_frame_msssim_y": 0.982760, + "ave_all_frame_msssim_u": 0.984277, + "ave_all_frame_msssim_v": 0.987070, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006018, + "ave_i_frame_psnr": 39.351045, + "ave_i_frame_msssim": 0.977172, + "ave_i_frame_psnr_y": 37.945530, + "ave_i_frame_psnr_u": 43.051154, + "ave_i_frame_psnr_v": 44.084023, + "ave_i_frame_msssim_y": 0.975334, + "ave_i_frame_msssim_u": 0.980537, + "ave_i_frame_msssim_v": 0.984833, + "test_time": 19472.606483, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006018, + "ave_all_frame_psnr": 39.351045, + "ave_all_frame_msssim": 0.977172, + "ave_all_frame_psnr_y": 37.945530, + "ave_all_frame_psnr_u": 43.051154, + "ave_all_frame_psnr_v": 44.084023, + "ave_all_frame_msssim_y": 0.975334, + "ave_all_frame_msssim_u": 0.980537, + "ave_all_frame_msssim_v": 0.984833, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004334, + "ave_i_frame_psnr": 37.794819, + "ave_i_frame_msssim": 0.968272, + "ave_i_frame_psnr_y": 36.165666, + "ave_i_frame_psnr_u": 42.206346, + "ave_i_frame_psnr_v": 43.158211, + "ave_i_frame_msssim_y": 0.964698, + "ave_i_frame_msssim_u": 0.976592, + "ave_i_frame_msssim_v": 0.981394, + "test_time": 15290.303777, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004334, + "ave_all_frame_psnr": 37.794819, + "ave_all_frame_msssim": 0.968272, + "ave_all_frame_psnr_y": 36.165666, + "ave_all_frame_psnr_u": 42.206346, + "ave_all_frame_psnr_v": 43.158211, + "ave_all_frame_msssim_y": 0.964698, + "ave_all_frame_msssim_u": 0.976592, + "ave_all_frame_msssim_v": 0.981394, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003085, + "ave_i_frame_psnr": 36.188119, + "ave_i_frame_msssim": 0.955448, + "ave_i_frame_psnr_y": 34.311228, + "ave_i_frame_psnr_u": 41.302958, + "ave_i_frame_psnr_v": 42.334624, + "ave_i_frame_msssim_y": 0.948979, + "ave_i_frame_msssim_u": 0.971686, + "ave_i_frame_msssim_v": 0.978022, + "test_time": 11942.484753, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003085, + "ave_all_frame_psnr": 36.188119, + "ave_all_frame_msssim": 0.955448, + "ave_all_frame_psnr_y": 34.311228, + "ave_all_frame_psnr_u": 41.302958, + "ave_all_frame_psnr_v": 42.334624, + "ave_all_frame_msssim_y": 0.948979, + "ave_all_frame_msssim_u": 0.971686, + "ave_all_frame_msssim_v": 0.978022, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002141, + "ave_i_frame_psnr": 34.499612, + "ave_i_frame_msssim": 0.936757, + "ave_i_frame_psnr_y": 32.477196, + "ave_i_frame_psnr_u": 40.168145, + "ave_i_frame_psnr_v": 40.965575, + "ave_i_frame_msssim_y": 0.926535, + "ave_i_frame_msssim_u": 0.964072, + "ave_i_frame_msssim_v": 0.970772, + "test_time": 9185.822150, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002141, + "ave_all_frame_psnr": 34.499612, + "ave_all_frame_msssim": 0.936757, + "ave_all_frame_psnr_y": 32.477196, + "ave_all_frame_psnr_u": 40.168145, + "ave_all_frame_psnr_v": 40.965575, + "ave_all_frame_msssim_y": 0.926535, + "ave_all_frame_msssim_u": 0.964072, + "ave_all_frame_msssim_v": 0.970772, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001476, + "ave_i_frame_psnr": 32.795272, + "ave_i_frame_msssim": 0.912324, + "ave_i_frame_psnr_y": 30.647520, + "ave_i_frame_psnr_u": 38.899986, + "ave_i_frame_psnr_v": 39.577070, + "ave_i_frame_msssim_y": 0.896604, + "ave_i_frame_msssim_u": 0.955805, + "ave_i_frame_msssim_v": 0.963159, + "test_time": 7187.655349, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001476, + "ave_all_frame_psnr": 32.795272, + "ave_all_frame_msssim": 0.912324, + "ave_all_frame_psnr_y": 30.647520, + "ave_all_frame_psnr_u": 38.899986, + "ave_all_frame_psnr_v": 39.577070, + "ave_all_frame_msssim_y": 0.896604, + "ave_all_frame_msssim_u": 0.955805, + "ave_all_frame_msssim_v": 0.963159, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC02_1920x1080_30.yuv" + } + }, + "videoSRC03_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016512, + "ave_i_frame_psnr": 44.674786, + "ave_i_frame_msssim": 0.994988, + "ave_i_frame_psnr_y": 43.643915, + "ave_i_frame_psnr_u": 45.607158, + "ave_i_frame_psnr_v": 49.927639, + "ave_i_frame_msssim_y": 0.994919, + "ave_i_frame_msssim_u": 0.993734, + "ave_i_frame_msssim_v": 0.996660, + "test_time": 44236.307603, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016512, + "ave_all_frame_psnr": 44.674786, + "ave_all_frame_msssim": 0.994988, + "ave_all_frame_psnr_y": 43.643915, + "ave_all_frame_psnr_u": 45.607158, + "ave_all_frame_psnr_v": 49.927639, + "ave_all_frame_msssim_y": 0.994919, + "ave_all_frame_msssim_u": 0.993734, + "ave_all_frame_msssim_v": 0.996660, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011233, + "ave_i_frame_psnr": 43.624993, + "ave_i_frame_msssim": 0.993586, + "ave_i_frame_psnr_y": 42.506139, + "ave_i_frame_psnr_u": 44.759710, + "ave_i_frame_psnr_v": 49.203399, + "ave_i_frame_msssim_y": 0.993473, + "ave_i_frame_msssim_u": 0.992028, + "ave_i_frame_msssim_v": 0.995826, + "test_time": 35219.500954, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011233, + "ave_all_frame_psnr": 43.624993, + "ave_all_frame_msssim": 0.993586, + "ave_all_frame_psnr_y": 42.506139, + "ave_all_frame_psnr_u": 44.759710, + "ave_all_frame_psnr_v": 49.203399, + "ave_all_frame_msssim_y": 0.993473, + "ave_all_frame_msssim_u": 0.992028, + "ave_all_frame_msssim_v": 0.995826, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007313, + "ave_i_frame_psnr": 42.364952, + "ave_i_frame_msssim": 0.991305, + "ave_i_frame_psnr_y": 41.108959, + "ave_i_frame_psnr_u": 43.811653, + "ave_i_frame_psnr_v": 48.454210, + "ave_i_frame_msssim_y": 0.990992, + "ave_i_frame_msssim_u": 0.989662, + "ave_i_frame_msssim_v": 0.994822, + "test_time": 26010.653607, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007313, + "ave_all_frame_psnr": 42.364952, + "ave_all_frame_msssim": 0.991305, + "ave_all_frame_psnr_y": 41.108959, + "ave_all_frame_psnr_u": 43.811653, + "ave_all_frame_psnr_v": 48.454210, + "ave_all_frame_msssim_y": 0.990992, + "ave_all_frame_msssim_u": 0.989662, + "ave_all_frame_msssim_v": 0.994822, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004828, + "ave_i_frame_psnr": 40.989590, + "ave_i_frame_msssim": 0.987884, + "ave_i_frame_psnr_y": 39.589347, + "ave_i_frame_psnr_u": 42.820492, + "ave_i_frame_psnr_v": 47.560144, + "ave_i_frame_msssim_y": 0.987209, + "ave_i_frame_msssim_u": 0.986450, + "ave_i_frame_msssim_v": 0.993373, + "test_time": 20165.356066, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004828, + "ave_all_frame_psnr": 40.989590, + "ave_all_frame_msssim": 0.987884, + "ave_all_frame_psnr_y": 39.589347, + "ave_all_frame_psnr_u": 42.820492, + "ave_all_frame_psnr_v": 47.560144, + "ave_all_frame_msssim_y": 0.987209, + "ave_all_frame_msssim_u": 0.986450, + "ave_all_frame_msssim_v": 0.993373, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003356, + "ave_i_frame_psnr": 39.653661, + "ave_i_frame_msssim": 0.983264, + "ave_i_frame_psnr_y": 38.124906, + "ave_i_frame_psnr_u": 41.807025, + "ave_i_frame_psnr_v": 46.672826, + "ave_i_frame_msssim_y": 0.982017, + "ave_i_frame_msssim_u": 0.982169, + "ave_i_frame_msssim_v": 0.991847, + "test_time": 15768.632849, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003356, + "ave_all_frame_psnr": 39.653661, + "ave_all_frame_msssim": 0.983264, + "ave_all_frame_psnr_y": 38.124906, + "ave_all_frame_psnr_u": 41.807025, + "ave_all_frame_psnr_v": 46.672826, + "ave_all_frame_msssim_y": 0.982017, + "ave_all_frame_msssim_u": 0.982169, + "ave_all_frame_msssim_v": 0.991847, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002329, + "ave_i_frame_psnr": 38.335563, + "ave_i_frame_msssim": 0.976878, + "ave_i_frame_psnr_y": 36.610457, + "ave_i_frame_psnr_u": 40.886445, + "ave_i_frame_psnr_v": 46.135316, + "ave_i_frame_msssim_y": 0.974424, + "ave_i_frame_msssim_u": 0.977961, + "ave_i_frame_msssim_v": 0.990516, + "test_time": 12881.451721, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002329, + "ave_all_frame_psnr": 38.335563, + "ave_all_frame_msssim": 0.976878, + "ave_all_frame_psnr_y": 36.610457, + "ave_all_frame_psnr_u": 40.886445, + "ave_all_frame_psnr_v": 46.135316, + "ave_all_frame_msssim_y": 0.974424, + "ave_all_frame_msssim_u": 0.977961, + "ave_all_frame_msssim_v": 0.990516, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001628, + "ave_i_frame_psnr": 37.010707, + "ave_i_frame_msssim": 0.967405, + "ave_i_frame_psnr_y": 35.046460, + "ave_i_frame_psnr_u": 40.170780, + "ave_i_frame_psnr_v": 45.636119, + "ave_i_frame_msssim_y": 0.962676, + "ave_i_frame_msssim_u": 0.973271, + "ave_i_frame_msssim_v": 0.989913, + "test_time": 10318.691969, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001628, + "ave_all_frame_psnr": 37.010707, + "ave_all_frame_msssim": 0.967405, + "ave_all_frame_psnr_y": 35.046460, + "ave_all_frame_psnr_u": 40.170780, + "ave_all_frame_psnr_v": 45.636119, + "ave_all_frame_msssim_y": 0.962676, + "ave_all_frame_msssim_u": 0.973271, + "ave_all_frame_msssim_v": 0.989913, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001147, + "ave_i_frame_psnr": 35.719287, + "ave_i_frame_msssim": 0.954029, + "ave_i_frame_psnr_y": 33.511820, + "ave_i_frame_psnr_u": 39.633745, + "ave_i_frame_psnr_v": 45.049628, + "ave_i_frame_msssim_y": 0.945774, + "ave_i_frame_msssim_u": 0.968962, + "ave_i_frame_msssim_v": 0.988629, + "test_time": 8020.057268, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001147, + "ave_all_frame_psnr": 35.719287, + "ave_all_frame_msssim": 0.954029, + "ave_all_frame_psnr_y": 33.511820, + "ave_all_frame_psnr_u": 39.633745, + "ave_all_frame_psnr_v": 45.049628, + "ave_all_frame_msssim_y": 0.945774, + "ave_all_frame_msssim_u": 0.968962, + "ave_all_frame_msssim_v": 0.988629, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000789, + "ave_i_frame_psnr": 34.241492, + "ave_i_frame_msssim": 0.933520, + "ave_i_frame_psnr_y": 31.908880, + "ave_i_frame_psnr_u": 38.560157, + "ave_i_frame_psnr_v": 43.918501, + "ave_i_frame_msssim_y": 0.920493, + "ave_i_frame_msssim_u": 0.959207, + "ave_i_frame_msssim_v": 0.985994, + "test_time": 6293.672657, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000789, + "ave_all_frame_psnr": 34.241492, + "ave_all_frame_msssim": 0.933520, + "ave_all_frame_psnr_y": 31.908880, + "ave_all_frame_psnr_u": 38.560157, + "ave_all_frame_psnr_v": 43.918501, + "ave_all_frame_msssim_y": 0.920493, + "ave_all_frame_msssim_u": 0.959207, + "ave_all_frame_msssim_v": 0.985994, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000530, + "ave_i_frame_psnr": 32.681901, + "ave_i_frame_msssim": 0.900873, + "ave_i_frame_psnr_y": 30.166721, + "ave_i_frame_psnr_u": 37.487656, + "ave_i_frame_psnr_v": 42.967231, + "ave_i_frame_msssim_y": 0.879126, + "ave_i_frame_msssim_u": 0.948146, + "ave_i_frame_msssim_v": 0.984079, + "test_time": 4981.863747, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000530, + "ave_all_frame_psnr": 32.681901, + "ave_all_frame_msssim": 0.900873, + "ave_all_frame_psnr_y": 30.166721, + "ave_all_frame_psnr_u": 37.487656, + "ave_all_frame_psnr_v": 42.967231, + "ave_all_frame_msssim_y": 0.879126, + "ave_all_frame_msssim_u": 0.948146, + "ave_all_frame_msssim_v": 0.984079, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC03_1920x1080_30.yuv" + } + }, + "videoSRC04_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.405771, + "ave_i_frame_psnr": 43.465071, + "ave_i_frame_msssim": 0.992921, + "ave_i_frame_psnr_y": 42.628998, + "ave_i_frame_psnr_u": 44.423423, + "ave_i_frame_psnr_v": 47.523158, + "ave_i_frame_msssim_y": 0.993450, + "ave_i_frame_msssim_u": 0.989079, + "ave_i_frame_msssim_v": 0.993590, + "test_time": 187127.385715, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.405771, + "ave_all_frame_psnr": 43.465071, + "ave_all_frame_msssim": 0.992921, + "ave_all_frame_psnr_y": 42.628998, + "ave_all_frame_psnr_u": 44.423423, + "ave_all_frame_psnr_v": 47.523158, + "ave_all_frame_msssim_y": 0.993450, + "ave_all_frame_msssim_u": 0.989079, + "ave_all_frame_msssim_v": 0.993590, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.263125, + "ave_i_frame_psnr": 41.356769, + "ave_i_frame_msssim": 0.987580, + "ave_i_frame_psnr_y": 40.202819, + "ave_i_frame_psnr_u": 43.177103, + "ave_i_frame_psnr_v": 46.460137, + "ave_i_frame_msssim_y": 0.987549, + "ave_i_frame_msssim_u": 0.983822, + "ave_i_frame_msssim_v": 0.991528, + "test_time": 157144.758463, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.263125, + "ave_all_frame_psnr": 41.356769, + "ave_all_frame_msssim": 0.987580, + "ave_all_frame_psnr_y": 40.202819, + "ave_all_frame_psnr_u": 43.177103, + "ave_all_frame_psnr_v": 46.460137, + "ave_all_frame_msssim_y": 0.987549, + "ave_all_frame_msssim_u": 0.983822, + "ave_all_frame_msssim_v": 0.991528, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.162454, + "ave_i_frame_psnr": 39.401959, + "ave_i_frame_msssim": 0.979034, + "ave_i_frame_psnr_y": 37.867335, + "ave_i_frame_psnr_u": 42.349587, + "ave_i_frame_psnr_v": 45.662076, + "ave_i_frame_msssim_y": 0.977116, + "ave_i_frame_msssim_u": 0.979777, + "ave_i_frame_msssim_v": 0.989797, + "test_time": 131304.015707, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.162454, + "ave_all_frame_psnr": 39.401959, + "ave_all_frame_msssim": 0.979034, + "ave_all_frame_psnr_y": 37.867335, + "ave_all_frame_psnr_u": 42.349587, + "ave_all_frame_psnr_v": 45.662076, + "ave_all_frame_msssim_y": 0.977116, + "ave_all_frame_msssim_u": 0.979777, + "ave_all_frame_msssim_v": 0.989797, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.095359, + "ave_i_frame_psnr": 37.614019, + "ave_i_frame_msssim": 0.965862, + "ave_i_frame_psnr_y": 35.674452, + "ave_i_frame_psnr_u": 41.853995, + "ave_i_frame_psnr_v": 45.011450, + "ave_i_frame_msssim_y": 0.960179, + "ave_i_frame_msssim_u": 0.977324, + "ave_i_frame_msssim_v": 0.988501, + "test_time": 101841.506240, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.095359, + "ave_all_frame_psnr": 37.614019, + "ave_all_frame_msssim": 0.965862, + "ave_all_frame_psnr_y": 35.674452, + "ave_all_frame_psnr_u": 41.853995, + "ave_all_frame_psnr_v": 45.011450, + "ave_all_frame_msssim_y": 0.960179, + "ave_all_frame_msssim_u": 0.977324, + "ave_all_frame_msssim_v": 0.988501, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.058990, + "ave_i_frame_psnr": 36.246725, + "ave_i_frame_msssim": 0.951381, + "ave_i_frame_psnr_y": 34.065744, + "ave_i_frame_psnr_u": 41.320320, + "ave_i_frame_psnr_v": 44.259016, + "ave_i_frame_msssim_y": 0.941706, + "ave_i_frame_msssim_u": 0.974119, + "ave_i_frame_msssim_v": 0.986689, + "test_time": 76530.304151, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.058990, + "ave_all_frame_psnr": 36.246725, + "ave_all_frame_msssim": 0.951381, + "ave_all_frame_psnr_y": 34.065744, + "ave_all_frame_psnr_u": 41.320320, + "ave_all_frame_psnr_v": 44.259016, + "ave_all_frame_msssim_y": 0.941706, + "ave_all_frame_msssim_u": 0.974119, + "ave_all_frame_msssim_v": 0.986689, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.034165, + "ave_i_frame_psnr": 34.915586, + "ave_i_frame_msssim": 0.932282, + "ave_i_frame_psnr_y": 32.559207, + "ave_i_frame_psnr_u": 40.310593, + "ave_i_frame_psnr_v": 43.658856, + "ave_i_frame_msssim_y": 0.917688, + "ave_i_frame_msssim_u": 0.967194, + "ave_i_frame_msssim_v": 0.984936, + "test_time": 57689.054710, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.034165, + "ave_all_frame_psnr": 34.915586, + "ave_all_frame_msssim": 0.932282, + "ave_all_frame_psnr_y": 32.559207, + "ave_all_frame_psnr_u": 40.310593, + "ave_all_frame_psnr_v": 43.658856, + "ave_all_frame_msssim_y": 0.917688, + "ave_all_frame_msssim_u": 0.967194, + "ave_all_frame_msssim_v": 0.984936, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.018486, + "ave_i_frame_psnr": 33.775189, + "ave_i_frame_msssim": 0.909512, + "ave_i_frame_psnr_y": 31.188181, + "ave_i_frame_psnr_u": 39.984320, + "ave_i_frame_psnr_v": 43.088111, + "ave_i_frame_msssim_y": 0.887817, + "ave_i_frame_msssim_u": 0.965672, + "ave_i_frame_msssim_v": 0.983527, + "test_time": 41618.691309, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.018486, + "ave_all_frame_psnr": 33.775189, + "ave_all_frame_msssim": 0.909512, + "ave_all_frame_psnr_y": 31.188181, + "ave_all_frame_psnr_u": 39.984320, + "ave_all_frame_psnr_v": 43.088111, + "ave_all_frame_msssim_y": 0.887817, + "ave_all_frame_msssim_u": 0.965672, + "ave_all_frame_msssim_v": 0.983527, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009376, + "ave_i_frame_psnr": 32.725143, + "ave_i_frame_msssim": 0.883090, + "ave_i_frame_psnr_y": 29.935266, + "ave_i_frame_psnr_u": 39.611927, + "ave_i_frame_psnr_v": 42.577625, + "ave_i_frame_msssim_y": 0.852981, + "ave_i_frame_msssim_u": 0.964143, + "ave_i_frame_msssim_v": 0.982692, + "test_time": 26618.528148, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009376, + "ave_all_frame_psnr": 32.725143, + "ave_all_frame_msssim": 0.883090, + "ave_all_frame_psnr_y": 29.935266, + "ave_all_frame_psnr_u": 39.611927, + "ave_all_frame_psnr_v": 42.577625, + "ave_all_frame_msssim_y": 0.852981, + "ave_all_frame_msssim_u": 0.964143, + "ave_all_frame_msssim_v": 0.982692, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004604, + "ave_i_frame_psnr": 31.684121, + "ave_i_frame_msssim": 0.855446, + "ave_i_frame_psnr_y": 28.822984, + "ave_i_frame_psnr_u": 39.193176, + "ave_i_frame_psnr_v": 41.341892, + "ave_i_frame_msssim_y": 0.816801, + "ave_i_frame_msssim_u": 0.962113, + "ave_i_frame_msssim_v": 0.980650, + "test_time": 16472.946220, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004604, + "ave_all_frame_psnr": 31.684121, + "ave_all_frame_msssim": 0.855446, + "ave_all_frame_psnr_y": 28.822984, + "ave_all_frame_psnr_u": 39.193176, + "ave_all_frame_psnr_v": 41.341892, + "ave_all_frame_msssim_y": 0.816801, + "ave_all_frame_msssim_u": 0.962113, + "ave_all_frame_msssim_v": 0.980650, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002234, + "ave_i_frame_psnr": 30.707103, + "ave_i_frame_msssim": 0.828624, + "ave_i_frame_psnr_y": 27.822476, + "ave_i_frame_psnr_u": 38.462729, + "ave_i_frame_psnr_v": 40.259234, + "ave_i_frame_msssim_y": 0.782085, + "ave_i_frame_msssim_u": 0.959112, + "ave_i_frame_msssim_v": 0.977372, + "test_time": 9845.680343, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002234, + "ave_all_frame_psnr": 30.707103, + "ave_all_frame_msssim": 0.828624, + "ave_all_frame_psnr_y": 27.822476, + "ave_all_frame_psnr_u": 38.462729, + "ave_all_frame_psnr_v": 40.259234, + "ave_all_frame_msssim_y": 0.782085, + "ave_all_frame_msssim_u": 0.959112, + "ave_all_frame_msssim_v": 0.977372, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC04_1920x1080_30.yuv" + } + }, + "videoSRC05_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.164229, + "ave_i_frame_psnr": 40.640488, + "ave_i_frame_msssim": 0.990900, + "ave_i_frame_psnr_y": 39.406796, + "ave_i_frame_psnr_u": 43.615451, + "ave_i_frame_psnr_v": 45.067681, + "ave_i_frame_msssim_y": 0.989948, + "ave_i_frame_msssim_u": 0.992546, + "ave_i_frame_msssim_v": 0.994971, + "test_time": 141232.237585, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.164229, + "ave_all_frame_psnr": 40.640488, + "ave_all_frame_msssim": 0.990900, + "ave_all_frame_psnr_y": 39.406796, + "ave_all_frame_psnr_u": 43.615451, + "ave_all_frame_psnr_v": 45.067681, + "ave_all_frame_msssim_y": 0.989948, + "ave_all_frame_msssim_u": 0.992546, + "ave_all_frame_msssim_v": 0.994971, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.085325, + "ave_i_frame_psnr": 39.532348, + "ave_i_frame_msssim": 0.987841, + "ave_i_frame_psnr_y": 38.276603, + "ave_i_frame_psnr_u": 42.813337, + "ave_i_frame_psnr_v": 43.785823, + "ave_i_frame_msssim_y": 0.986557, + "ave_i_frame_msssim_u": 0.990357, + "ave_i_frame_msssim_v": 0.993033, + "test_time": 100742.085434, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.085325, + "ave_all_frame_psnr": 39.532348, + "ave_all_frame_msssim": 0.987841, + "ave_all_frame_psnr_y": 38.276603, + "ave_all_frame_psnr_u": 42.813337, + "ave_all_frame_psnr_v": 43.785823, + "ave_all_frame_msssim_y": 0.986557, + "ave_all_frame_msssim_u": 0.990357, + "ave_all_frame_msssim_v": 0.993033, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.051328, + "ave_i_frame_psnr": 38.434332, + "ave_i_frame_msssim": 0.983659, + "ave_i_frame_psnr_y": 37.163879, + "ave_i_frame_psnr_u": 41.991437, + "ave_i_frame_psnr_v": 42.499941, + "ave_i_frame_msssim_y": 0.981868, + "ave_i_frame_msssim_u": 0.987621, + "ave_i_frame_msssim_v": 0.990442, + "test_time": 72827.181302, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.051328, + "ave_all_frame_psnr": 38.434332, + "ave_all_frame_msssim": 0.983659, + "ave_all_frame_psnr_y": 37.163879, + "ave_all_frame_psnr_u": 41.991437, + "ave_all_frame_psnr_v": 42.499941, + "ave_all_frame_msssim_y": 0.981868, + "ave_all_frame_msssim_u": 0.987621, + "ave_all_frame_msssim_v": 0.990442, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.032236, + "ave_i_frame_psnr": 37.271973, + "ave_i_frame_msssim": 0.977782, + "ave_i_frame_psnr_y": 35.893354, + "ave_i_frame_psnr_u": 41.281927, + "ave_i_frame_psnr_v": 41.533732, + "ave_i_frame_msssim_y": 0.974944, + "ave_i_frame_msssim_u": 0.984762, + "ave_i_frame_msssim_v": 0.987829, + "test_time": 55016.516677, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.032236, + "ave_all_frame_psnr": 37.271973, + "ave_all_frame_msssim": 0.977782, + "ave_all_frame_psnr_y": 35.893354, + "ave_all_frame_psnr_u": 41.281927, + "ave_all_frame_psnr_v": 41.533732, + "ave_all_frame_msssim_y": 0.974944, + "ave_all_frame_msssim_u": 0.984762, + "ave_all_frame_msssim_v": 0.987829, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.021936, + "ave_i_frame_psnr": 36.167557, + "ave_i_frame_msssim": 0.970664, + "ave_i_frame_psnr_y": 34.736574, + "ave_i_frame_psnr_u": 40.497154, + "ave_i_frame_psnr_v": 40.423861, + "ave_i_frame_msssim_y": 0.966732, + "ave_i_frame_msssim_u": 0.980881, + "ave_i_frame_msssim_v": 0.984043, + "test_time": 41797.237873, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.021936, + "ave_all_frame_psnr": 36.167557, + "ave_all_frame_msssim": 0.970664, + "ave_all_frame_psnr_y": 34.736574, + "ave_all_frame_psnr_u": 40.497154, + "ave_all_frame_psnr_v": 40.423861, + "ave_all_frame_msssim_y": 0.966732, + "ave_all_frame_msssim_u": 0.980881, + "ave_all_frame_msssim_v": 0.984043, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014863, + "ave_i_frame_psnr": 35.005887, + "ave_i_frame_msssim": 0.961464, + "ave_i_frame_psnr_y": 33.485349, + "ave_i_frame_psnr_u": 39.732659, + "ave_i_frame_psnr_v": 39.402343, + "ave_i_frame_msssim_y": 0.955654, + "ave_i_frame_msssim_u": 0.977315, + "ave_i_frame_msssim_v": 0.980472, + "test_time": 32489.229065, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014863, + "ave_all_frame_psnr": 35.005887, + "ave_all_frame_msssim": 0.961464, + "ave_all_frame_psnr_y": 33.485349, + "ave_all_frame_psnr_u": 39.732659, + "ave_all_frame_psnr_v": 39.402343, + "ave_all_frame_msssim_y": 0.955654, + "ave_all_frame_msssim_u": 0.977315, + "ave_all_frame_msssim_v": 0.980472, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009944, + "ave_i_frame_psnr": 33.743330, + "ave_i_frame_msssim": 0.948512, + "ave_i_frame_psnr_y": 32.143135, + "ave_i_frame_psnr_u": 38.888820, + "ave_i_frame_psnr_v": 38.199008, + "ave_i_frame_msssim_y": 0.940283, + "ave_i_frame_msssim_u": 0.971918, + "ave_i_frame_msssim_v": 0.974481, + "test_time": 24216.515391, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009944, + "ave_all_frame_psnr": 33.743330, + "ave_all_frame_msssim": 0.948512, + "ave_all_frame_psnr_y": 32.143135, + "ave_all_frame_psnr_u": 38.888820, + "ave_all_frame_psnr_v": 38.199008, + "ave_all_frame_msssim_y": 0.940283, + "ave_all_frame_msssim_u": 0.971918, + "ave_all_frame_msssim_v": 0.974481, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006617, + "ave_i_frame_psnr": 32.458238, + "ave_i_frame_msssim": 0.931809, + "ave_i_frame_psnr_y": 30.741748, + "ave_i_frame_psnr_u": 38.109198, + "ave_i_frame_psnr_v": 37.106213, + "ave_i_frame_msssim_y": 0.919976, + "ave_i_frame_msssim_u": 0.966112, + "ave_i_frame_msssim_v": 0.968505, + "test_time": 18451.344161, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006617, + "ave_all_frame_psnr": 32.458238, + "ave_all_frame_msssim": 0.931809, + "ave_all_frame_psnr_y": 30.741748, + "ave_all_frame_psnr_u": 38.109198, + "ave_all_frame_psnr_v": 37.106213, + "ave_all_frame_msssim_y": 0.919976, + "ave_all_frame_msssim_u": 0.966112, + "ave_all_frame_msssim_v": 0.968505, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004341, + "ave_i_frame_psnr": 31.077187, + "ave_i_frame_msssim": 0.910062, + "ave_i_frame_psnr_y": 29.319068, + "ave_i_frame_psnr_u": 36.985211, + "ave_i_frame_psnr_v": 35.717873, + "ave_i_frame_msssim_y": 0.894492, + "ave_i_frame_msssim_u": 0.955731, + "ave_i_frame_msssim_v": 0.957818, + "test_time": 13433.515820, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004341, + "ave_all_frame_psnr": 31.077187, + "ave_all_frame_msssim": 0.910062, + "ave_all_frame_psnr_y": 29.319068, + "ave_all_frame_psnr_u": 36.985211, + "ave_all_frame_psnr_v": 35.717873, + "ave_all_frame_msssim_y": 0.894492, + "ave_all_frame_msssim_u": 0.955731, + "ave_all_frame_msssim_v": 0.957818, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002799, + "ave_i_frame_psnr": 29.622512, + "ave_i_frame_msssim": 0.881147, + "ave_i_frame_psnr_y": 27.827504, + "ave_i_frame_psnr_u": 35.807178, + "ave_i_frame_psnr_v": 34.207891, + "ave_i_frame_msssim_y": 0.860894, + "ave_i_frame_msssim_u": 0.942696, + "ave_i_frame_msssim_v": 0.941117, + "test_time": 9367.681541, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002799, + "ave_all_frame_psnr": 29.622512, + "ave_all_frame_msssim": 0.881147, + "ave_all_frame_psnr_y": 27.827504, + "ave_all_frame_psnr_u": 35.807178, + "ave_all_frame_psnr_v": 34.207891, + "ave_all_frame_msssim_y": 0.860894, + "ave_all_frame_msssim_u": 0.942696, + "ave_all_frame_msssim_v": 0.941117, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC05_1920x1080_25.yuv" + } + }, + "videoSRC06_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.465317, + "ave_i_frame_psnr": 37.190141, + "ave_i_frame_msssim": 0.974948, + "ave_i_frame_psnr_y": 36.594257, + "ave_i_frame_psnr_u": 37.755761, + "ave_i_frame_psnr_v": 40.199827, + "ave_i_frame_msssim_y": 0.973108, + "ave_i_frame_msssim_u": 0.975280, + "ave_i_frame_msssim_v": 0.985660, + "test_time": 300827.568917, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.465317, + "ave_all_frame_psnr": 37.190141, + "ave_all_frame_msssim": 0.974948, + "ave_all_frame_psnr_y": 36.594257, + "ave_all_frame_psnr_u": 37.755761, + "ave_all_frame_psnr_v": 40.199827, + "ave_all_frame_msssim_y": 0.973108, + "ave_all_frame_msssim_u": 0.975280, + "ave_all_frame_msssim_v": 0.985660, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.074282, + "ave_i_frame_psnr": 35.331061, + "ave_i_frame_msssim": 0.949722, + "ave_i_frame_psnr_y": 34.181838, + "ave_i_frame_psnr_u": 37.433101, + "ave_i_frame_psnr_v": 40.124353, + "ave_i_frame_msssim_y": 0.940039, + "ave_i_frame_msssim_u": 0.972407, + "ave_i_frame_msssim_v": 0.985135, + "test_time": 90872.218913, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.074282, + "ave_all_frame_psnr": 35.331061, + "ave_all_frame_msssim": 0.949722, + "ave_all_frame_psnr_y": 34.181838, + "ave_all_frame_psnr_u": 37.433101, + "ave_all_frame_psnr_v": 40.124353, + "ave_all_frame_msssim_y": 0.940039, + "ave_all_frame_msssim_u": 0.972407, + "ave_all_frame_msssim_v": 0.985135, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009442, + "ave_i_frame_psnr": 34.942676, + "ave_i_frame_msssim": 0.943249, + "ave_i_frame_psnr_y": 33.696870, + "ave_i_frame_psnr_u": 37.339405, + "ave_i_frame_psnr_v": 40.020781, + "ave_i_frame_msssim_y": 0.931609, + "ave_i_frame_msssim_u": 0.971608, + "ave_i_frame_msssim_v": 0.984727, + "test_time": 27786.914722, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009442, + "ave_all_frame_psnr": 34.942676, + "ave_all_frame_msssim": 0.943249, + "ave_all_frame_psnr_y": 33.696870, + "ave_all_frame_psnr_u": 37.339405, + "ave_all_frame_psnr_v": 40.020781, + "ave_all_frame_msssim_y": 0.931609, + "ave_all_frame_msssim_u": 0.971608, + "ave_all_frame_msssim_v": 0.984727, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001614, + "ave_i_frame_psnr": 34.796076, + "ave_i_frame_msssim": 0.941099, + "ave_i_frame_psnr_y": 33.532243, + "ave_i_frame_psnr_u": 37.251384, + "ave_i_frame_psnr_v": 39.923768, + "ave_i_frame_msssim_y": 0.929011, + "ave_i_frame_msssim_u": 0.970728, + "ave_i_frame_msssim_v": 0.983991, + "test_time": 14152.323898, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001614, + "ave_all_frame_psnr": 34.796076, + "ave_all_frame_msssim": 0.941099, + "ave_all_frame_psnr_y": 33.532243, + "ave_all_frame_psnr_u": 37.251384, + "ave_all_frame_psnr_v": 39.923768, + "ave_all_frame_msssim_y": 0.929011, + "ave_all_frame_msssim_u": 0.970728, + "ave_all_frame_msssim_v": 0.983991, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000853, + "ave_i_frame_psnr": 34.649008, + "ave_i_frame_msssim": 0.939194, + "ave_i_frame_psnr_y": 33.385222, + "ave_i_frame_psnr_u": 37.134151, + "ave_i_frame_psnr_v": 39.746581, + "ave_i_frame_msssim_y": 0.926865, + "ave_i_frame_msssim_u": 0.969470, + "ave_i_frame_msssim_v": 0.982894, + "test_time": 10962.472635, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000853, + "ave_all_frame_psnr": 34.649008, + "ave_all_frame_msssim": 0.939194, + "ave_all_frame_psnr_y": 33.385222, + "ave_all_frame_psnr_u": 37.134151, + "ave_all_frame_psnr_v": 39.746581, + "ave_all_frame_msssim_y": 0.926865, + "ave_all_frame_msssim_u": 0.969470, + "ave_all_frame_msssim_v": 0.982894, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000535, + "ave_i_frame_psnr": 34.492956, + "ave_i_frame_msssim": 0.936983, + "ave_i_frame_psnr_y": 33.198950, + "ave_i_frame_psnr_u": 37.067938, + "ave_i_frame_psnr_v": 39.682009, + "ave_i_frame_msssim_y": 0.924082, + "ave_i_frame_msssim_u": 0.968904, + "ave_i_frame_msssim_v": 0.982470, + "test_time": 8357.931826, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000535, + "ave_all_frame_psnr": 34.492956, + "ave_all_frame_msssim": 0.936983, + "ave_all_frame_psnr_y": 33.198950, + "ave_all_frame_psnr_u": 37.067938, + "ave_all_frame_psnr_v": 39.682009, + "ave_all_frame_msssim_y": 0.924082, + "ave_all_frame_msssim_u": 0.968904, + "ave_all_frame_msssim_v": 0.982470, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000363, + "ave_i_frame_psnr": 34.291719, + "ave_i_frame_msssim": 0.934129, + "ave_i_frame_psnr_y": 32.971967, + "ave_i_frame_psnr_u": 36.967342, + "ave_i_frame_psnr_v": 39.534607, + "ave_i_frame_msssim_y": 0.920652, + "ave_i_frame_msssim_u": 0.967797, + "ave_i_frame_msssim_v": 0.981321, + "test_time": 6862.482112, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000363, + "ave_all_frame_psnr": 34.291719, + "ave_all_frame_msssim": 0.934129, + "ave_all_frame_psnr_y": 32.971967, + "ave_all_frame_psnr_u": 36.967342, + "ave_all_frame_psnr_v": 39.534607, + "ave_all_frame_msssim_y": 0.920652, + "ave_all_frame_msssim_u": 0.967797, + "ave_all_frame_msssim_v": 0.981321, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000256, + "ave_i_frame_psnr": 34.029008, + "ave_i_frame_msssim": 0.930738, + "ave_i_frame_psnr_y": 32.680139, + "ave_i_frame_psnr_u": 36.823304, + "ave_i_frame_psnr_v": 39.327928, + "ave_i_frame_msssim_y": 0.916524, + "ave_i_frame_msssim_u": 0.966571, + "ave_i_frame_msssim_v": 0.980186, + "test_time": 5118.846046, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000256, + "ave_all_frame_psnr": 34.029008, + "ave_all_frame_msssim": 0.930738, + "ave_all_frame_psnr_y": 32.680139, + "ave_all_frame_psnr_u": 36.823304, + "ave_all_frame_psnr_v": 39.327928, + "ave_all_frame_msssim_y": 0.916524, + "ave_all_frame_msssim_u": 0.966571, + "ave_all_frame_msssim_v": 0.980186, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000200, + "ave_i_frame_psnr": 33.653761, + "ave_i_frame_msssim": 0.925894, + "ave_i_frame_psnr_y": 32.295949, + "ave_i_frame_psnr_u": 36.457851, + "ave_i_frame_psnr_v": 38.996541, + "ave_i_frame_msssim_y": 0.910640, + "ave_i_frame_msssim_u": 0.964804, + "ave_i_frame_msssim_v": 0.978506, + "test_time": 3503.023026, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000200, + "ave_all_frame_psnr": 33.653761, + "ave_all_frame_msssim": 0.925894, + "ave_all_frame_psnr_y": 32.295949, + "ave_all_frame_psnr_u": 36.457851, + "ave_all_frame_psnr_v": 38.996541, + "ave_all_frame_msssim_y": 0.910640, + "ave_all_frame_msssim_u": 0.964804, + "ave_all_frame_msssim_v": 0.978506, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000160, + "ave_i_frame_psnr": 33.199809, + "ave_i_frame_msssim": 0.920711, + "ave_i_frame_psnr_y": 31.867338, + "ave_i_frame_psnr_u": 35.937220, + "ave_i_frame_psnr_v": 38.457223, + "ave_i_frame_msssim_y": 0.904694, + "ave_i_frame_msssim_u": 0.961396, + "ave_i_frame_msssim_v": 0.976134, + "test_time": 2957.009072, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000160, + "ave_all_frame_psnr": 33.199809, + "ave_all_frame_msssim": 0.920711, + "ave_all_frame_psnr_y": 31.867338, + "ave_all_frame_psnr_u": 35.937220, + "ave_all_frame_psnr_v": 38.457223, + "ave_all_frame_msssim_y": 0.904694, + "ave_all_frame_msssim_u": 0.961396, + "ave_all_frame_msssim_v": 0.976134, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC06_1920x1080_25.yuv" + } + }, + "videoSRC07_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.176933, + "ave_i_frame_psnr": 39.779594, + "ave_i_frame_msssim": 0.986189, + "ave_i_frame_psnr_y": 38.985832, + "ave_i_frame_psnr_u": 41.632659, + "ave_i_frame_psnr_v": 42.689102, + "ave_i_frame_msssim_y": 0.985181, + "ave_i_frame_msssim_u": 0.988540, + "ave_i_frame_msssim_v": 0.989887, + "test_time": 196093.722005, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.176933, + "ave_all_frame_psnr": 39.779594, + "ave_all_frame_msssim": 0.986189, + "ave_all_frame_psnr_y": 38.985832, + "ave_all_frame_psnr_u": 41.632659, + "ave_all_frame_psnr_v": 42.689102, + "ave_all_frame_msssim_y": 0.985181, + "ave_all_frame_msssim_u": 0.988540, + "ave_all_frame_msssim_v": 0.989887, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.068743, + "ave_i_frame_psnr": 38.787904, + "ave_i_frame_msssim": 0.980549, + "ave_i_frame_psnr_y": 37.839520, + "ave_i_frame_psnr_u": 41.307516, + "ave_i_frame_psnr_v": 41.958600, + "ave_i_frame_msssim_y": 0.978430, + "ave_i_frame_msssim_u": 0.986839, + "ave_i_frame_msssim_v": 0.986972, + "test_time": 127676.317681, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.068743, + "ave_all_frame_psnr": 38.787904, + "ave_all_frame_msssim": 0.980549, + "ave_all_frame_psnr_y": 37.839520, + "ave_all_frame_psnr_u": 41.307516, + "ave_all_frame_psnr_v": 41.958600, + "ave_all_frame_msssim_y": 0.978430, + "ave_all_frame_msssim_u": 0.986839, + "ave_all_frame_msssim_v": 0.986972, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.034819, + "ave_i_frame_psnr": 38.011735, + "ave_i_frame_msssim": 0.974101, + "ave_i_frame_psnr_y": 36.970787, + "ave_i_frame_psnr_u": 40.998737, + "ave_i_frame_psnr_v": 41.270420, + "ave_i_frame_msssim_y": 0.970603, + "ave_i_frame_msssim_u": 0.985200, + "ave_i_frame_msssim_v": 0.983986, + "test_time": 84237.853458, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.034819, + "ave_all_frame_psnr": 38.011735, + "ave_all_frame_msssim": 0.974101, + "ave_all_frame_psnr_y": 36.970787, + "ave_all_frame_psnr_u": 40.998737, + "ave_all_frame_psnr_v": 41.270420, + "ave_all_frame_msssim_y": 0.970603, + "ave_all_frame_msssim_u": 0.985200, + "ave_all_frame_msssim_v": 0.983986, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.019166, + "ave_i_frame_psnr": 37.200696, + "ave_i_frame_msssim": 0.965547, + "ave_i_frame_psnr_y": 36.034162, + "ave_i_frame_psnr_u": 40.701747, + "ave_i_frame_psnr_v": 40.698848, + "ave_i_frame_msssim_y": 0.959952, + "ave_i_frame_msssim_u": 0.983469, + "ave_i_frame_msssim_v": 0.981195, + "test_time": 57297.682549, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.019166, + "ave_all_frame_psnr": 37.200696, + "ave_all_frame_msssim": 0.965547, + "ave_all_frame_psnr_y": 36.034162, + "ave_all_frame_psnr_u": 40.701747, + "ave_all_frame_psnr_v": 40.698848, + "ave_all_frame_msssim_y": 0.959952, + "ave_all_frame_msssim_u": 0.983469, + "ave_all_frame_msssim_v": 0.981195, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011730, + "ave_i_frame_psnr": 36.442979, + "ave_i_frame_msssim": 0.956458, + "ave_i_frame_psnr_y": 35.185973, + "ave_i_frame_psnr_u": 40.350947, + "ave_i_frame_psnr_v": 40.077047, + "ave_i_frame_msssim_y": 0.948720, + "ave_i_frame_msssim_u": 0.981603, + "ave_i_frame_msssim_v": 0.977736, + "test_time": 37919.591464, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011730, + "ave_all_frame_psnr": 36.442979, + "ave_all_frame_msssim": 0.956458, + "ave_all_frame_psnr_y": 35.185973, + "ave_all_frame_psnr_u": 40.350947, + "ave_all_frame_psnr_v": 40.077047, + "ave_all_frame_msssim_y": 0.948720, + "ave_all_frame_msssim_u": 0.981603, + "ave_all_frame_msssim_v": 0.977736, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007105, + "ave_i_frame_psnr": 35.612848, + "ave_i_frame_msssim": 0.944986, + "ave_i_frame_psnr_y": 34.271850, + "ave_i_frame_psnr_u": 39.898107, + "ave_i_frame_psnr_v": 39.373577, + "ave_i_frame_msssim_y": 0.934698, + "ave_i_frame_msssim_u": 0.978107, + "ave_i_frame_msssim_v": 0.973593, + "test_time": 25336.794655, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007105, + "ave_all_frame_psnr": 35.612848, + "ave_all_frame_msssim": 0.944986, + "ave_all_frame_psnr_y": 34.271850, + "ave_all_frame_psnr_u": 39.898107, + "ave_all_frame_psnr_v": 39.373577, + "ave_all_frame_msssim_y": 0.934698, + "ave_all_frame_msssim_u": 0.978107, + "ave_all_frame_msssim_v": 0.973593, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004277, + "ave_i_frame_psnr": 34.770685, + "ave_i_frame_msssim": 0.931685, + "ave_i_frame_psnr_y": 33.318433, + "ave_i_frame_psnr_u": 39.492972, + "ave_i_frame_psnr_v": 38.761904, + "ave_i_frame_msssim_y": 0.918040, + "ave_i_frame_msssim_u": 0.975427, + "ave_i_frame_msssim_v": 0.969816, + "test_time": 16063.364281, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004277, + "ave_all_frame_psnr": 34.770685, + "ave_all_frame_msssim": 0.931685, + "ave_all_frame_psnr_y": 33.318433, + "ave_all_frame_psnr_u": 39.492972, + "ave_all_frame_psnr_v": 38.761904, + "ave_all_frame_msssim_y": 0.918040, + "ave_all_frame_msssim_u": 0.975427, + "ave_all_frame_msssim_v": 0.969816, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002594, + "ave_i_frame_psnr": 33.935401, + "ave_i_frame_msssim": 0.916540, + "ave_i_frame_psnr_y": 32.338411, + "ave_i_frame_psnr_u": 39.220605, + "ave_i_frame_psnr_v": 38.232130, + "ave_i_frame_msssim_y": 0.898871, + "ave_i_frame_msssim_u": 0.973395, + "ave_i_frame_msssim_v": 0.965698, + "test_time": 10409.223014, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002594, + "ave_all_frame_psnr": 33.935401, + "ave_all_frame_msssim": 0.916540, + "ave_all_frame_psnr_y": 32.338411, + "ave_all_frame_psnr_u": 39.220605, + "ave_all_frame_psnr_v": 38.232130, + "ave_all_frame_msssim_y": 0.898871, + "ave_all_frame_msssim_u": 0.973395, + "ave_all_frame_msssim_v": 0.965698, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001585, + "ave_i_frame_psnr": 33.009555, + "ave_i_frame_msssim": 0.900041, + "ave_i_frame_psnr_y": 31.350059, + "ave_i_frame_psnr_u": 38.643764, + "ave_i_frame_psnr_v": 37.332326, + "ave_i_frame_msssim_y": 0.878785, + "ave_i_frame_msssim_u": 0.969391, + "ave_i_frame_msssim_v": 0.958228, + "test_time": 7130.373932, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001585, + "ave_all_frame_psnr": 33.009555, + "ave_all_frame_msssim": 0.900041, + "ave_all_frame_psnr_y": 31.350059, + "ave_all_frame_psnr_u": 38.643764, + "ave_all_frame_psnr_v": 37.332326, + "ave_all_frame_msssim_y": 0.878785, + "ave_all_frame_msssim_u": 0.969391, + "ave_all_frame_msssim_v": 0.958228, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000992, + "ave_i_frame_psnr": 32.047410, + "ave_i_frame_msssim": 0.882744, + "ave_i_frame_psnr_y": 30.345394, + "ave_i_frame_psnr_u": 37.803888, + "ave_i_frame_psnr_v": 36.503029, + "ave_i_frame_msssim_y": 0.858474, + "ave_i_frame_msssim_u": 0.963670, + "ave_i_frame_msssim_v": 0.947438, + "test_time": 4872.223256, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000992, + "ave_all_frame_psnr": 32.047410, + "ave_all_frame_msssim": 0.882744, + "ave_all_frame_psnr_y": 30.345394, + "ave_all_frame_psnr_u": 37.803888, + "ave_all_frame_psnr_v": 36.503029, + "ave_all_frame_msssim_y": 0.858474, + "ave_all_frame_msssim_u": 0.963670, + "ave_all_frame_msssim_v": 0.947438, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC07_1920x1080_25.yuv" + } + }, + "videoSRC08_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.035773, + "ave_i_frame_psnr": 42.034398, + "ave_i_frame_msssim": 0.990515, + "ave_i_frame_psnr_y": 41.282140, + "ave_i_frame_psnr_u": 42.191337, + "ave_i_frame_psnr_v": 46.391006, + "ave_i_frame_msssim_y": 0.989802, + "ave_i_frame_msssim_u": 0.989801, + "ave_i_frame_msssim_v": 0.995508, + "test_time": 54644.700493, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.035773, + "ave_all_frame_psnr": 42.034398, + "ave_all_frame_msssim": 0.990515, + "ave_all_frame_psnr_y": 41.282140, + "ave_all_frame_psnr_u": 42.191337, + "ave_all_frame_psnr_v": 46.391006, + "ave_all_frame_msssim_y": 0.989802, + "ave_all_frame_msssim_u": 0.989801, + "ave_all_frame_msssim_v": 0.995508, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017238, + "ave_i_frame_psnr": 41.391115, + "ave_i_frame_msssim": 0.989216, + "ave_i_frame_psnr_y": 40.583041, + "ave_i_frame_psnr_u": 41.995352, + "ave_i_frame_psnr_v": 45.635321, + "ave_i_frame_msssim_y": 0.988438, + "ave_i_frame_msssim_u": 0.988786, + "ave_i_frame_msssim_v": 0.994308, + "test_time": 36178.170698, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017238, + "ave_all_frame_psnr": 41.391115, + "ave_all_frame_msssim": 0.989216, + "ave_all_frame_psnr_y": 40.583041, + "ave_all_frame_psnr_u": 41.995352, + "ave_all_frame_psnr_v": 45.635321, + "ave_all_frame_msssim_y": 0.988438, + "ave_all_frame_msssim_u": 0.988786, + "ave_all_frame_msssim_v": 0.994308, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009716, + "ave_i_frame_psnr": 40.679937, + "ave_i_frame_msssim": 0.987376, + "ave_i_frame_psnr_y": 39.804839, + "ave_i_frame_psnr_u": 41.765320, + "ave_i_frame_psnr_v": 44.845140, + "ave_i_frame_msssim_y": 0.986448, + "ave_i_frame_msssim_u": 0.987550, + "ave_i_frame_msssim_v": 0.992772, + "test_time": 25855.857386, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009716, + "ave_all_frame_psnr": 40.679937, + "ave_all_frame_msssim": 0.987376, + "ave_all_frame_psnr_y": 39.804839, + "ave_all_frame_psnr_u": 41.765320, + "ave_all_frame_psnr_v": 44.845140, + "ave_all_frame_msssim_y": 0.986448, + "ave_all_frame_msssim_u": 0.987550, + "ave_all_frame_msssim_v": 0.992772, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005836, + "ave_i_frame_psnr": 39.872576, + "ave_i_frame_msssim": 0.984654, + "ave_i_frame_psnr_y": 38.876524, + "ave_i_frame_psnr_u": 41.509255, + "ave_i_frame_psnr_v": 44.212214, + "ave_i_frame_msssim_y": 0.983406, + "ave_i_frame_msssim_u": 0.986007, + "ave_i_frame_msssim_v": 0.990786, + "test_time": 18685.937007, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005836, + "ave_all_frame_psnr": 39.872576, + "ave_all_frame_msssim": 0.984654, + "ave_all_frame_psnr_y": 38.876524, + "ave_all_frame_psnr_u": 41.509255, + "ave_all_frame_psnr_v": 44.212214, + "ave_all_frame_msssim_y": 0.983406, + "ave_all_frame_msssim_u": 0.986007, + "ave_all_frame_msssim_v": 0.990786, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003773, + "ave_i_frame_psnr": 38.996647, + "ave_i_frame_msssim": 0.981064, + "ave_i_frame_psnr_y": 37.891235, + "ave_i_frame_psnr_u": 41.218697, + "ave_i_frame_psnr_v": 43.407070, + "ave_i_frame_msssim_y": 0.979312, + "ave_i_frame_msssim_u": 0.984312, + "ave_i_frame_msssim_v": 0.988331, + "test_time": 13690.309737, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003773, + "ave_all_frame_psnr": 38.996647, + "ave_all_frame_msssim": 0.981064, + "ave_all_frame_psnr_y": 37.891235, + "ave_all_frame_psnr_u": 41.218697, + "ave_all_frame_psnr_v": 43.407070, + "ave_all_frame_msssim_y": 0.979312, + "ave_all_frame_msssim_u": 0.984312, + "ave_all_frame_msssim_v": 0.988331, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002485, + "ave_i_frame_psnr": 38.058403, + "ave_i_frame_msssim": 0.976262, + "ave_i_frame_psnr_y": 36.799630, + "ave_i_frame_psnr_u": 40.985142, + "ave_i_frame_psnr_v": 42.684302, + "ave_i_frame_msssim_y": 0.973539, + "ave_i_frame_msssim_u": 0.982951, + "ave_i_frame_msssim_v": 0.985905, + "test_time": 10517.676416, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002485, + "ave_all_frame_psnr": 38.058403, + "ave_all_frame_msssim": 0.976262, + "ave_all_frame_psnr_y": 36.799630, + "ave_all_frame_psnr_u": 40.985142, + "ave_all_frame_psnr_v": 42.684302, + "ave_all_frame_msssim_y": 0.973539, + "ave_all_frame_msssim_u": 0.982951, + "ave_all_frame_msssim_v": 0.985905, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001674, + "ave_i_frame_psnr": 37.062646, + "ave_i_frame_msssim": 0.969811, + "ave_i_frame_psnr_y": 35.635920, + "ave_i_frame_psnr_u": 40.646209, + "ave_i_frame_psnr_v": 42.039444, + "ave_i_frame_msssim_y": 0.965774, + "ave_i_frame_msssim_u": 0.980939, + "ave_i_frame_msssim_v": 0.982906, + "test_time": 7846.042061, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001674, + "ave_all_frame_psnr": 37.062646, + "ave_all_frame_msssim": 0.969811, + "ave_all_frame_psnr_y": 35.635920, + "ave_all_frame_psnr_u": 40.646209, + "ave_all_frame_psnr_v": 42.039444, + "ave_all_frame_msssim_y": 0.965774, + "ave_all_frame_msssim_u": 0.980939, + "ave_all_frame_msssim_v": 0.982906, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001154, + "ave_i_frame_psnr": 36.043384, + "ave_i_frame_msssim": 0.961985, + "ave_i_frame_psnr_y": 34.434923, + "ave_i_frame_psnr_u": 40.395997, + "ave_i_frame_psnr_v": 41.341533, + "ave_i_frame_msssim_y": 0.956015, + "ave_i_frame_msssim_u": 0.979678, + "ave_i_frame_msssim_v": 0.980117, + "test_time": 6098.952999, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001154, + "ave_all_frame_psnr": 36.043384, + "ave_all_frame_msssim": 0.961985, + "ave_all_frame_psnr_y": 34.434923, + "ave_all_frame_psnr_u": 40.395997, + "ave_all_frame_psnr_v": 41.341533, + "ave_all_frame_msssim_y": 0.956015, + "ave_all_frame_msssim_u": 0.979678, + "ave_all_frame_msssim_v": 0.980117, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000803, + "ave_i_frame_psnr": 34.875282, + "ave_i_frame_msssim": 0.950819, + "ave_i_frame_psnr_y": 33.146509, + "ave_i_frame_psnr_u": 39.807950, + "ave_i_frame_psnr_v": 40.315251, + "ave_i_frame_msssim_y": 0.942711, + "ave_i_frame_msssim_u": 0.976299, + "ave_i_frame_msssim_v": 0.973989, + "test_time": 4808.363773, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000803, + "ave_all_frame_psnr": 34.875282, + "ave_all_frame_msssim": 0.950819, + "ave_all_frame_psnr_y": 33.146509, + "ave_all_frame_psnr_u": 39.807950, + "ave_all_frame_psnr_v": 40.315251, + "ave_all_frame_msssim_y": 0.942711, + "ave_all_frame_msssim_u": 0.976299, + "ave_all_frame_msssim_v": 0.973989, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000564, + "ave_i_frame_psnr": 33.702488, + "ave_i_frame_msssim": 0.938189, + "ave_i_frame_psnr_y": 31.869012, + "ave_i_frame_psnr_u": 39.153433, + "ave_i_frame_psnr_v": 39.252395, + "ave_i_frame_msssim_y": 0.927704, + "ave_i_frame_msssim_u": 0.971910, + "ave_i_frame_msssim_v": 0.967379, + "test_time": 3824.319446, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000564, + "ave_all_frame_psnr": 33.702488, + "ave_all_frame_msssim": 0.938189, + "ave_all_frame_psnr_y": 31.869012, + "ave_all_frame_psnr_u": 39.153433, + "ave_all_frame_psnr_v": 39.252395, + "ave_all_frame_msssim_y": 0.927704, + "ave_all_frame_msssim_u": 0.971910, + "ave_all_frame_msssim_v": 0.967379, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC08_1920x1080_25.yuv" + } + }, + "videoSRC09_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.323114, + "ave_i_frame_psnr": 39.971523, + "ave_i_frame_msssim": 0.993716, + "ave_i_frame_psnr_y": 39.294112, + "ave_i_frame_psnr_u": 41.647682, + "ave_i_frame_psnr_v": 42.359827, + "ave_i_frame_msssim_y": 0.995319, + "ave_i_frame_msssim_u": 0.987404, + "ave_i_frame_msssim_v": 0.990408, + "test_time": 124519.450385, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.323114, + "ave_all_frame_psnr": 39.971523, + "ave_all_frame_msssim": 0.993716, + "ave_all_frame_psnr_y": 39.294112, + "ave_all_frame_psnr_u": 41.647682, + "ave_all_frame_psnr_v": 42.359827, + "ave_all_frame_msssim_y": 0.995319, + "ave_all_frame_msssim_u": 0.987404, + "ave_all_frame_msssim_v": 0.990408, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.150180, + "ave_i_frame_psnr": 37.987134, + "ave_i_frame_msssim": 0.990512, + "ave_i_frame_psnr_y": 37.060167, + "ave_i_frame_psnr_u": 40.549970, + "ave_i_frame_psnr_v": 40.986106, + "ave_i_frame_msssim_y": 0.992375, + "ave_i_frame_msssim_u": 0.983177, + "ave_i_frame_msssim_v": 0.986670, + "test_time": 104925.794096, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.150180, + "ave_all_frame_psnr": 37.987134, + "ave_all_frame_msssim": 0.990512, + "ave_all_frame_psnr_y": 37.060167, + "ave_all_frame_psnr_u": 40.549970, + "ave_all_frame_psnr_v": 40.986106, + "ave_all_frame_msssim_y": 0.992375, + "ave_all_frame_msssim_u": 0.983177, + "ave_all_frame_msssim_v": 0.986670, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.083944, + "ave_i_frame_psnr": 36.344409, + "ave_i_frame_msssim": 0.985958, + "ave_i_frame_psnr_y": 35.268486, + "ave_i_frame_psnr_u": 39.497940, + "ave_i_frame_psnr_v": 39.646419, + "ave_i_frame_msssim_y": 0.988033, + "ave_i_frame_msssim_u": 0.977876, + "ave_i_frame_msssim_v": 0.981591, + "test_time": 77653.495215, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.083944, + "ave_all_frame_psnr": 36.344409, + "ave_all_frame_msssim": 0.985958, + "ave_all_frame_psnr_y": 35.268486, + "ave_all_frame_psnr_u": 39.497940, + "ave_all_frame_psnr_v": 39.646419, + "ave_all_frame_msssim_y": 0.988033, + "ave_all_frame_msssim_u": 0.977876, + "ave_all_frame_msssim_v": 0.981591, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.050829, + "ave_i_frame_psnr": 34.760547, + "ave_i_frame_msssim": 0.979284, + "ave_i_frame_psnr_y": 33.506926, + "ave_i_frame_psnr_u": 38.548478, + "ave_i_frame_psnr_v": 38.494346, + "ave_i_frame_msssim_y": 0.981126, + "ave_i_frame_msssim_u": 0.971753, + "ave_i_frame_msssim_v": 0.975764, + "test_time": 58875.412637, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.050829, + "ave_all_frame_psnr": 34.760547, + "ave_all_frame_msssim": 0.979284, + "ave_all_frame_psnr_y": 33.506926, + "ave_all_frame_psnr_u": 38.548478, + "ave_all_frame_psnr_v": 38.494346, + "ave_all_frame_msssim_y": 0.981126, + "ave_all_frame_msssim_u": 0.971753, + "ave_all_frame_msssim_v": 0.975764, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.033575, + "ave_i_frame_psnr": 33.339828, + "ave_i_frame_msssim": 0.970579, + "ave_i_frame_psnr_y": 31.992056, + "ave_i_frame_psnr_u": 37.477291, + "ave_i_frame_psnr_v": 37.288993, + "ave_i_frame_msssim_y": 0.972335, + "ave_i_frame_msssim_u": 0.962907, + "ave_i_frame_msssim_v": 0.967721, + "test_time": 44581.589788, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.033575, + "ave_all_frame_psnr": 33.339828, + "ave_all_frame_msssim": 0.970579, + "ave_all_frame_psnr_y": 31.992056, + "ave_all_frame_psnr_u": 37.477291, + "ave_all_frame_psnr_v": 37.288993, + "ave_all_frame_msssim_y": 0.972335, + "ave_all_frame_msssim_u": 0.962907, + "ave_all_frame_msssim_v": 0.967721, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022119, + "ave_i_frame_psnr": 31.941551, + "ave_i_frame_msssim": 0.958495, + "ave_i_frame_psnr_y": 30.422771, + "ave_i_frame_psnr_u": 36.619594, + "ave_i_frame_psnr_v": 36.376189, + "ave_i_frame_msssim_y": 0.958960, + "ave_i_frame_msssim_u": 0.954166, + "ave_i_frame_msssim_v": 0.960041, + "test_time": 34661.926497, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022119, + "ave_all_frame_psnr": 31.941551, + "ave_all_frame_msssim": 0.958495, + "ave_all_frame_psnr_y": 30.422771, + "ave_all_frame_psnr_u": 36.619594, + "ave_all_frame_psnr_v": 36.376189, + "ave_all_frame_msssim_y": 0.958960, + "ave_all_frame_msssim_u": 0.954166, + "ave_all_frame_msssim_v": 0.960041, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014310, + "ave_i_frame_psnr": 30.495218, + "ave_i_frame_msssim": 0.940506, + "ave_i_frame_psnr_y": 28.810817, + "ave_i_frame_psnr_u": 35.753310, + "ave_i_frame_psnr_v": 35.343531, + "ave_i_frame_msssim_y": 0.938488, + "ave_i_frame_msssim_u": 0.943436, + "ave_i_frame_msssim_v": 0.949684, + "test_time": 26940.820774, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014310, + "ave_all_frame_psnr": 30.495218, + "ave_all_frame_msssim": 0.940506, + "ave_all_frame_psnr_y": 28.810817, + "ave_all_frame_psnr_u": 35.753310, + "ave_all_frame_psnr_v": 35.343531, + "ave_all_frame_msssim_y": 0.938488, + "ave_all_frame_msssim_u": 0.943436, + "ave_all_frame_msssim_v": 0.949684, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009039, + "ave_i_frame_psnr": 29.084922, + "ave_i_frame_msssim": 0.914349, + "ave_i_frame_psnr_y": 27.189374, + "ave_i_frame_psnr_u": 35.097687, + "ave_i_frame_psnr_v": 34.445442, + "ave_i_frame_msssim_y": 0.906798, + "ave_i_frame_msssim_u": 0.934038, + "ave_i_frame_msssim_v": 0.939959, + "test_time": 19899.106715, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009039, + "ave_all_frame_psnr": 29.084922, + "ave_all_frame_msssim": 0.914349, + "ave_all_frame_psnr_y": 27.189374, + "ave_all_frame_psnr_u": 35.097687, + "ave_all_frame_psnr_v": 34.445442, + "ave_all_frame_msssim_y": 0.906798, + "ave_all_frame_msssim_u": 0.934038, + "ave_all_frame_msssim_v": 0.939959, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005541, + "ave_i_frame_psnr": 27.601420, + "ave_i_frame_msssim": 0.874672, + "ave_i_frame_psnr_y": 25.637489, + "ave_i_frame_psnr_u": 33.889960, + "ave_i_frame_psnr_v": 33.096467, + "ave_i_frame_msssim_y": 0.860771, + "ave_i_frame_msssim_u": 0.913155, + "ave_i_frame_msssim_v": 0.919597, + "test_time": 15003.215292, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005541, + "ave_all_frame_psnr": 27.601420, + "ave_all_frame_msssim": 0.874672, + "ave_all_frame_psnr_y": 25.637489, + "ave_all_frame_psnr_u": 33.889960, + "ave_all_frame_psnr_v": 33.096467, + "ave_all_frame_msssim_y": 0.860771, + "ave_all_frame_msssim_u": 0.913155, + "ave_all_frame_msssim_v": 0.919597, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003350, + "ave_i_frame_psnr": 26.219807, + "ave_i_frame_msssim": 0.826678, + "ave_i_frame_psnr_y": 24.211155, + "ave_i_frame_psnr_u": 32.764329, + "ave_i_frame_psnr_v": 31.727199, + "ave_i_frame_msssim_y": 0.804933, + "ave_i_frame_msssim_u": 0.890106, + "ave_i_frame_msssim_v": 0.893714, + "test_time": 9921.757558, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003350, + "ave_all_frame_psnr": 26.219807, + "ave_all_frame_msssim": 0.826678, + "ave_all_frame_psnr_y": 24.211155, + "ave_all_frame_psnr_u": 32.764329, + "ave_all_frame_psnr_v": 31.727199, + "ave_all_frame_msssim_y": 0.804933, + "ave_all_frame_msssim_u": 0.890106, + "ave_all_frame_msssim_v": 0.893714, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC09_1920x1080_25.yuv" + } + }, + "videoSRC10_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.160380, + "ave_i_frame_psnr": 42.611144, + "ave_i_frame_msssim": 0.995643, + "ave_i_frame_psnr_y": 41.390484, + "ave_i_frame_psnr_u": 45.216368, + "ave_i_frame_psnr_v": 47.329879, + "ave_i_frame_msssim_y": 0.996205, + "ave_i_frame_msssim_u": 0.992881, + "ave_i_frame_msssim_v": 0.995036, + "test_time": 183900.831546, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.160380, + "ave_all_frame_psnr": 42.611144, + "ave_all_frame_msssim": 0.995643, + "ave_all_frame_psnr_y": 41.390484, + "ave_all_frame_psnr_u": 45.216368, + "ave_all_frame_psnr_v": 47.329879, + "ave_all_frame_msssim_y": 0.996205, + "ave_all_frame_msssim_u": 0.992881, + "ave_all_frame_msssim_v": 0.995036, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.095367, + "ave_i_frame_psnr": 40.831931, + "ave_i_frame_msssim": 0.993513, + "ave_i_frame_psnr_y": 39.359908, + "ave_i_frame_psnr_u": 44.120247, + "ave_i_frame_psnr_v": 46.375754, + "ave_i_frame_msssim_y": 0.994128, + "ave_i_frame_msssim_u": 0.989915, + "ave_i_frame_msssim_v": 0.993422, + "test_time": 146706.442130, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.095367, + "ave_all_frame_psnr": 40.831931, + "ave_all_frame_msssim": 0.993513, + "ave_all_frame_psnr_y": 39.359908, + "ave_all_frame_psnr_u": 44.120247, + "ave_all_frame_psnr_v": 46.375754, + "ave_all_frame_msssim_y": 0.994128, + "ave_all_frame_msssim_u": 0.989915, + "ave_all_frame_msssim_v": 0.993422, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.057699, + "ave_i_frame_psnr": 39.116948, + "ave_i_frame_msssim": 0.990363, + "ave_i_frame_psnr_y": 37.407526, + "ave_i_frame_psnr_u": 43.079035, + "ave_i_frame_psnr_v": 45.411392, + "ave_i_frame_msssim_y": 0.990859, + "ave_i_frame_msssim_u": 0.986291, + "ave_i_frame_msssim_v": 0.991459, + "test_time": 107670.669130, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.057699, + "ave_all_frame_psnr": 39.116948, + "ave_all_frame_msssim": 0.990363, + "ave_all_frame_psnr_y": 37.407526, + "ave_all_frame_psnr_u": 43.079035, + "ave_all_frame_psnr_v": 45.411392, + "ave_all_frame_msssim_y": 0.990859, + "ave_all_frame_msssim_u": 0.986291, + "ave_all_frame_msssim_v": 0.991459, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.035892, + "ave_i_frame_psnr": 37.535228, + "ave_i_frame_msssim": 0.986445, + "ave_i_frame_psnr_y": 35.563722, + "ave_i_frame_psnr_u": 42.217600, + "ave_i_frame_psnr_v": 44.681894, + "ave_i_frame_msssim_y": 0.986460, + "ave_i_frame_msssim_u": 0.982852, + "ave_i_frame_msssim_v": 0.989941, + "test_time": 82266.602621, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.035892, + "ave_all_frame_psnr": 37.535228, + "ave_all_frame_msssim": 0.986445, + "ave_all_frame_psnr_y": 35.563722, + "ave_all_frame_psnr_u": 42.217600, + "ave_all_frame_psnr_v": 44.681894, + "ave_all_frame_msssim_y": 0.986460, + "ave_all_frame_msssim_u": 0.982852, + "ave_all_frame_msssim_v": 0.989941, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.024579, + "ave_i_frame_psnr": 36.224124, + "ave_i_frame_msssim": 0.982589, + "ave_i_frame_psnr_y": 34.090043, + "ave_i_frame_psnr_u": 41.453442, + "ave_i_frame_psnr_v": 43.799297, + "ave_i_frame_msssim_y": 0.982190, + "ave_i_frame_msssim_u": 0.979446, + "ave_i_frame_msssim_v": 0.988124, + "test_time": 60319.111665, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.024579, + "ave_all_frame_psnr": 36.224124, + "ave_all_frame_msssim": 0.982589, + "ave_all_frame_psnr_y": 34.090043, + "ave_all_frame_psnr_u": 41.453442, + "ave_all_frame_psnr_v": 43.799297, + "ave_all_frame_msssim_y": 0.982190, + "ave_all_frame_msssim_u": 0.979446, + "ave_all_frame_msssim_v": 0.988124, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017229, + "ave_i_frame_psnr": 34.598961, + "ave_i_frame_msssim": 0.976029, + "ave_i_frame_psnr_y": 32.617236, + "ave_i_frame_psnr_u": 39.140675, + "ave_i_frame_psnr_v": 41.947600, + "ave_i_frame_msssim_y": 0.977135, + "ave_i_frame_msssim_u": 0.964432, + "ave_i_frame_msssim_v": 0.980990, + "test_time": 50077.292815, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017229, + "ave_all_frame_psnr": 34.598961, + "ave_all_frame_msssim": 0.976029, + "ave_all_frame_psnr_y": 32.617236, + "ave_all_frame_psnr_u": 39.140675, + "ave_all_frame_psnr_v": 41.947600, + "ave_all_frame_msssim_y": 0.977135, + "ave_all_frame_msssim_u": 0.964432, + "ave_all_frame_msssim_v": 0.980990, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012314, + "ave_i_frame_psnr": 33.313880, + "ave_i_frame_msssim": 0.969874, + "ave_i_frame_psnr_y": 31.059681, + "ave_i_frame_psnr_u": 38.624326, + "ave_i_frame_psnr_v": 41.528624, + "ave_i_frame_msssim_y": 0.969887, + "ave_i_frame_msssim_u": 0.960231, + "ave_i_frame_msssim_v": 0.979441, + "test_time": 38804.370248, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012314, + "ave_all_frame_psnr": 33.313880, + "ave_all_frame_msssim": 0.969874, + "ave_all_frame_psnr_y": 31.059681, + "ave_all_frame_psnr_u": 38.624326, + "ave_all_frame_psnr_v": 41.528624, + "ave_all_frame_msssim_y": 0.969887, + "ave_all_frame_msssim_u": 0.960231, + "ave_all_frame_msssim_v": 0.979441, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008923, + "ave_i_frame_psnr": 31.996609, + "ave_i_frame_msssim": 0.961196, + "ave_i_frame_psnr_y": 29.424219, + "ave_i_frame_psnr_u": 38.230741, + "ave_i_frame_psnr_v": 41.196821, + "ave_i_frame_msssim_y": 0.958906, + "ave_i_frame_msssim_u": 0.957322, + "ave_i_frame_msssim_v": 0.978808, + "test_time": 29860.771398, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008923, + "ave_all_frame_psnr": 31.996609, + "ave_all_frame_msssim": 0.961196, + "ave_all_frame_psnr_y": 29.424219, + "ave_all_frame_psnr_u": 38.230741, + "ave_all_frame_psnr_v": 41.196821, + "ave_all_frame_msssim_y": 0.958906, + "ave_all_frame_msssim_u": 0.957322, + "ave_all_frame_msssim_v": 0.978808, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006479, + "ave_i_frame_psnr": 30.568968, + "ave_i_frame_msssim": 0.947921, + "ave_i_frame_psnr_y": 27.725829, + "ave_i_frame_psnr_u": 37.657974, + "ave_i_frame_psnr_v": 40.538791, + "ave_i_frame_msssim_y": 0.942721, + "ave_i_frame_msssim_u": 0.951706, + "ave_i_frame_msssim_v": 0.975340, + "test_time": 21692.370028, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006479, + "ave_all_frame_psnr": 30.568968, + "ave_all_frame_msssim": 0.947921, + "ave_all_frame_psnr_y": 27.725829, + "ave_all_frame_psnr_u": 37.657974, + "ave_all_frame_psnr_v": 40.538791, + "ave_all_frame_msssim_y": 0.942721, + "ave_all_frame_msssim_u": 0.951706, + "ave_all_frame_msssim_v": 0.975340, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004687, + "ave_i_frame_psnr": 29.108151, + "ave_i_frame_msssim": 0.928820, + "ave_i_frame_psnr_y": 25.951378, + "ave_i_frame_psnr_u": 37.361562, + "ave_i_frame_psnr_v": 39.795374, + "ave_i_frame_msssim_y": 0.917875, + "ave_i_frame_msssim_u": 0.950367, + "ave_i_frame_msssim_v": 0.972940, + "test_time": 14252.227386, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004687, + "ave_all_frame_psnr": 29.108151, + "ave_all_frame_msssim": 0.928820, + "ave_all_frame_psnr_y": 25.951378, + "ave_all_frame_psnr_u": 37.361562, + "ave_all_frame_psnr_v": 39.795374, + "ave_all_frame_msssim_y": 0.917875, + "ave_all_frame_msssim_u": 0.950367, + "ave_all_frame_msssim_v": 0.972940, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC10_1920x1080_30.yuv" + } + }, + "videoSRC11_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.065574, + "ave_i_frame_psnr": 46.433201, + "ave_i_frame_msssim": 0.996302, + "ave_i_frame_psnr_y": 45.145234, + "ave_i_frame_psnr_u": 50.428910, + "ave_i_frame_psnr_v": 50.165290, + "ave_i_frame_msssim_y": 0.996117, + "ave_i_frame_msssim_u": 0.996946, + "ave_i_frame_msssim_v": 0.996771, + "test_time": 82811.708329, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.065574, + "ave_all_frame_psnr": 46.433201, + "ave_all_frame_msssim": 0.996302, + "ave_all_frame_psnr_y": 45.145234, + "ave_all_frame_psnr_u": 50.428910, + "ave_all_frame_psnr_v": 50.165290, + "ave_all_frame_msssim_y": 0.996117, + "ave_all_frame_msssim_u": 0.996946, + "ave_all_frame_msssim_v": 0.996771, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.041428, + "ave_i_frame_psnr": 44.803302, + "ave_i_frame_msssim": 0.994428, + "ave_i_frame_psnr_y": 43.350275, + "ave_i_frame_psnr_u": 49.251300, + "ave_i_frame_psnr_v": 49.073466, + "ave_i_frame_msssim_y": 0.994004, + "ave_i_frame_msssim_u": 0.995788, + "ave_i_frame_msssim_v": 0.995608, + "test_time": 65989.796992, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.041428, + "ave_all_frame_psnr": 44.803302, + "ave_all_frame_msssim": 0.994428, + "ave_all_frame_psnr_y": 43.350275, + "ave_all_frame_psnr_u": 49.251300, + "ave_all_frame_psnr_v": 49.073466, + "ave_all_frame_msssim_y": 0.994004, + "ave_all_frame_msssim_u": 0.995788, + "ave_all_frame_msssim_v": 0.995608, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.026063, + "ave_i_frame_psnr": 43.112924, + "ave_i_frame_msssim": 0.991523, + "ave_i_frame_psnr_y": 41.490083, + "ave_i_frame_psnr_u": 48.090105, + "ave_i_frame_psnr_v": 47.872789, + "ave_i_frame_msssim_y": 0.990654, + "ave_i_frame_msssim_u": 0.994218, + "ave_i_frame_msssim_v": 0.994039, + "test_time": 51344.577588, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.026063, + "ave_all_frame_psnr": 43.112924, + "ave_all_frame_msssim": 0.991523, + "ave_all_frame_psnr_y": 41.490083, + "ave_all_frame_psnr_u": 48.090105, + "ave_all_frame_psnr_v": 47.872789, + "ave_all_frame_msssim_y": 0.990654, + "ave_all_frame_msssim_u": 0.994218, + "ave_all_frame_msssim_v": 0.994039, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016707, + "ave_i_frame_psnr": 41.449754, + "ave_i_frame_msssim": 0.987289, + "ave_i_frame_psnr_y": 39.607043, + "ave_i_frame_psnr_u": 47.107483, + "ave_i_frame_psnr_v": 46.848286, + "ave_i_frame_msssim_y": 0.985565, + "ave_i_frame_msssim_u": 0.992619, + "ave_i_frame_msssim_v": 0.992302, + "test_time": 39126.227303, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016707, + "ave_all_frame_psnr": 41.449754, + "ave_all_frame_msssim": 0.987289, + "ave_all_frame_psnr_y": 39.607043, + "ave_all_frame_psnr_u": 47.107483, + "ave_all_frame_psnr_v": 46.848286, + "ave_all_frame_msssim_y": 0.985565, + "ave_all_frame_msssim_u": 0.992619, + "ave_all_frame_msssim_v": 0.992302, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011484, + "ave_i_frame_psnr": 39.995412, + "ave_i_frame_msssim": 0.982214, + "ave_i_frame_psnr_y": 38.054816, + "ave_i_frame_psnr_u": 45.876106, + "ave_i_frame_psnr_v": 45.758290, + "ave_i_frame_msssim_y": 0.979541, + "ave_i_frame_msssim_u": 0.990268, + "ave_i_frame_msssim_v": 0.990202, + "test_time": 30076.423692, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011484, + "ave_all_frame_psnr": 39.995412, + "ave_all_frame_msssim": 0.982214, + "ave_all_frame_psnr_y": 38.054816, + "ave_all_frame_psnr_u": 45.876106, + "ave_all_frame_psnr_v": 45.758290, + "ave_all_frame_msssim_y": 0.979541, + "ave_all_frame_msssim_u": 0.990268, + "ave_all_frame_msssim_v": 0.990202, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007937, + "ave_i_frame_psnr": 38.616889, + "ave_i_frame_msssim": 0.975516, + "ave_i_frame_psnr_y": 36.461834, + "ave_i_frame_psnr_u": 45.153031, + "ave_i_frame_psnr_v": 45.011079, + "ave_i_frame_msssim_y": 0.971197, + "ave_i_frame_msssim_u": 0.988433, + "ave_i_frame_msssim_v": 0.988511, + "test_time": 23529.658572, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007937, + "ave_all_frame_psnr": 38.616889, + "ave_all_frame_msssim": 0.975516, + "ave_all_frame_psnr_y": 36.461834, + "ave_all_frame_psnr_u": 45.153031, + "ave_all_frame_psnr_v": 45.011079, + "ave_all_frame_msssim_y": 0.971197, + "ave_all_frame_msssim_u": 0.988433, + "ave_all_frame_msssim_v": 0.988511, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005482, + "ave_i_frame_psnr": 37.185395, + "ave_i_frame_msssim": 0.966553, + "ave_i_frame_psnr_y": 34.871475, + "ave_i_frame_psnr_u": 44.145298, + "ave_i_frame_psnr_v": 44.109013, + "ave_i_frame_msssim_y": 0.960032, + "ave_i_frame_msssim_u": 0.986088, + "ave_i_frame_msssim_v": 0.986144, + "test_time": 18074.047097, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005482, + "ave_all_frame_psnr": 37.185395, + "ave_all_frame_msssim": 0.966553, + "ave_all_frame_psnr_y": 34.871475, + "ave_all_frame_psnr_u": 44.145298, + "ave_all_frame_psnr_v": 44.109013, + "ave_all_frame_msssim_y": 0.960032, + "ave_all_frame_msssim_u": 0.986088, + "ave_all_frame_msssim_v": 0.986144, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003798, + "ave_i_frame_psnr": 35.740273, + "ave_i_frame_msssim": 0.954583, + "ave_i_frame_psnr_y": 33.246188, + "ave_i_frame_psnr_u": 43.410728, + "ave_i_frame_psnr_v": 43.034323, + "ave_i_frame_msssim_y": 0.945011, + "ave_i_frame_msssim_u": 0.983631, + "ave_i_frame_msssim_v": 0.982965, + "test_time": 13777.808720, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003798, + "ave_all_frame_psnr": 35.740273, + "ave_all_frame_msssim": 0.954583, + "ave_all_frame_psnr_y": 33.246188, + "ave_all_frame_psnr_u": 43.410728, + "ave_all_frame_psnr_v": 43.034323, + "ave_all_frame_msssim_y": 0.945011, + "ave_all_frame_msssim_u": 0.983631, + "ave_all_frame_msssim_v": 0.982965, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002604, + "ave_i_frame_psnr": 34.114962, + "ave_i_frame_msssim": 0.938322, + "ave_i_frame_psnr_y": 31.594114, + "ave_i_frame_psnr_u": 41.876157, + "ave_i_frame_psnr_v": 41.478853, + "ave_i_frame_msssim_y": 0.924964, + "ave_i_frame_msssim_u": 0.978827, + "ave_i_frame_msssim_v": 0.977964, + "test_time": 10452.553939, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002604, + "ave_all_frame_psnr": 34.114962, + "ave_all_frame_msssim": 0.938322, + "ave_all_frame_psnr_y": 31.594114, + "ave_all_frame_psnr_u": 41.876157, + "ave_all_frame_psnr_v": 41.478853, + "ave_all_frame_msssim_y": 0.924964, + "ave_all_frame_msssim_u": 0.978827, + "ave_all_frame_msssim_v": 0.977964, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001793, + "ave_i_frame_psnr": 32.516700, + "ave_i_frame_msssim": 0.917858, + "ave_i_frame_psnr_y": 29.977109, + "ave_i_frame_psnr_u": 40.368010, + "ave_i_frame_psnr_v": 39.902934, + "ave_i_frame_msssim_y": 0.899604, + "ave_i_frame_msssim_u": 0.973060, + "ave_i_frame_msssim_v": 0.972183, + "test_time": 7841.419232, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001793, + "ave_all_frame_psnr": 32.516700, + "ave_all_frame_msssim": 0.917858, + "ave_all_frame_psnr_y": 29.977109, + "ave_all_frame_psnr_u": 40.368010, + "ave_all_frame_psnr_v": 39.902934, + "ave_all_frame_msssim_y": 0.899604, + "ave_all_frame_msssim_u": 0.973060, + "ave_all_frame_msssim_v": 0.972183, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC11_1920x1080_30.yuv" + } + }, + "videoSRC12_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.062942, + "ave_i_frame_psnr": 43.475754, + "ave_i_frame_msssim": 0.995180, + "ave_i_frame_psnr_y": 42.454535, + "ave_i_frame_psnr_u": 46.009145, + "ave_i_frame_psnr_v": 47.069675, + "ave_i_frame_msssim_y": 0.995666, + "ave_i_frame_msssim_u": 0.993429, + "ave_i_frame_msssim_v": 0.994022, + "test_time": 98632.059238, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.062942, + "ave_all_frame_psnr": 43.475754, + "ave_all_frame_msssim": 0.995180, + "ave_all_frame_psnr_y": 42.454535, + "ave_all_frame_psnr_u": 46.009145, + "ave_all_frame_psnr_v": 47.069675, + "ave_all_frame_msssim_y": 0.995666, + "ave_all_frame_msssim_u": 0.993429, + "ave_all_frame_msssim_v": 0.994022, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.031578, + "ave_i_frame_psnr": 41.711555, + "ave_i_frame_msssim": 0.992359, + "ave_i_frame_psnr_y": 40.471409, + "ave_i_frame_psnr_u": 44.901681, + "ave_i_frame_psnr_v": 45.962304, + "ave_i_frame_msssim_y": 0.992743, + "ave_i_frame_msssim_u": 0.990753, + "ave_i_frame_msssim_v": 0.991665, + "test_time": 70726.316728, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.031578, + "ave_all_frame_psnr": 41.711555, + "ave_all_frame_msssim": 0.992359, + "ave_all_frame_psnr_y": 40.471409, + "ave_all_frame_psnr_u": 44.901681, + "ave_all_frame_psnr_v": 45.962304, + "ave_all_frame_msssim_y": 0.992743, + "ave_all_frame_msssim_u": 0.990753, + "ave_all_frame_msssim_v": 0.991665, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017300, + "ave_i_frame_psnr": 40.164278, + "ave_i_frame_msssim": 0.988490, + "ave_i_frame_psnr_y": 38.755859, + "ave_i_frame_psnr_u": 43.871488, + "ave_i_frame_psnr_v": 44.907582, + "ave_i_frame_msssim_y": 0.988626, + "ave_i_frame_msssim_u": 0.987403, + "ave_i_frame_msssim_v": 0.988762, + "test_time": 49675.753919, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017300, + "ave_all_frame_psnr": 40.164278, + "ave_all_frame_msssim": 0.988490, + "ave_all_frame_psnr_y": 38.755859, + "ave_all_frame_psnr_u": 43.871488, + "ave_all_frame_psnr_v": 44.907582, + "ave_all_frame_msssim_y": 0.988626, + "ave_all_frame_msssim_u": 0.987403, + "ave_all_frame_msssim_v": 0.988762, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009855, + "ave_i_frame_psnr": 38.682229, + "ave_i_frame_msssim": 0.983013, + "ave_i_frame_psnr_y": 37.100328, + "ave_i_frame_psnr_u": 42.900746, + "ave_i_frame_psnr_v": 43.955120, + "ave_i_frame_msssim_y": 0.982604, + "ave_i_frame_msssim_u": 0.983165, + "ave_i_frame_msssim_v": 0.985319, + "test_time": 32512.212807, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009855, + "ave_all_frame_psnr": 38.682229, + "ave_all_frame_msssim": 0.983013, + "ave_all_frame_psnr_y": 37.100328, + "ave_all_frame_psnr_u": 42.900746, + "ave_all_frame_psnr_v": 43.955120, + "ave_all_frame_msssim_y": 0.982604, + "ave_all_frame_msssim_u": 0.983165, + "ave_all_frame_msssim_v": 0.985319, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006110, + "ave_i_frame_psnr": 37.337334, + "ave_i_frame_msssim": 0.976121, + "ave_i_frame_psnr_y": 35.631772, + "ave_i_frame_psnr_u": 41.916676, + "ave_i_frame_psnr_v": 42.991366, + "ave_i_frame_msssim_y": 0.974926, + "ave_i_frame_msssim_u": 0.978208, + "ave_i_frame_msssim_v": 0.981204, + "test_time": 23767.033055, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006110, + "ave_all_frame_psnr": 37.337334, + "ave_all_frame_msssim": 0.976121, + "ave_all_frame_psnr_y": 35.631772, + "ave_all_frame_psnr_u": 41.916676, + "ave_all_frame_psnr_v": 42.991366, + "ave_all_frame_msssim_y": 0.974926, + "ave_all_frame_msssim_u": 0.978208, + "ave_all_frame_msssim_v": 0.981204, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003742, + "ave_i_frame_psnr": 36.048996, + "ave_i_frame_msssim": 0.967049, + "ave_i_frame_psnr_y": 34.178418, + "ave_i_frame_psnr_u": 40.986641, + "ave_i_frame_psnr_v": 42.334817, + "ave_i_frame_msssim_y": 0.964098, + "ave_i_frame_msssim_u": 0.973260, + "ave_i_frame_msssim_v": 0.978540, + "test_time": 17089.628114, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003742, + "ave_all_frame_psnr": 36.048996, + "ave_all_frame_msssim": 0.967049, + "ave_all_frame_psnr_y": 34.178418, + "ave_all_frame_psnr_u": 40.986641, + "ave_all_frame_psnr_v": 42.334817, + "ave_all_frame_msssim_y": 0.964098, + "ave_all_frame_msssim_u": 0.973260, + "ave_all_frame_msssim_v": 0.978540, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002291, + "ave_i_frame_psnr": 34.784446, + "ave_i_frame_msssim": 0.954779, + "ave_i_frame_psnr_y": 32.745031, + "ave_i_frame_psnr_u": 40.261801, + "ave_i_frame_psnr_v": 41.543585, + "ave_i_frame_msssim_y": 0.949301, + "ave_i_frame_msssim_u": 0.968059, + "ave_i_frame_msssim_v": 0.974364, + "test_time": 12341.530187, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002291, + "ave_all_frame_psnr": 34.784446, + "ave_all_frame_msssim": 0.954779, + "ave_all_frame_psnr_y": 32.745031, + "ave_all_frame_psnr_u": 40.261801, + "ave_all_frame_psnr_v": 41.543585, + "ave_all_frame_msssim_y": 0.949301, + "ave_all_frame_msssim_u": 0.968059, + "ave_all_frame_msssim_v": 0.974364, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001418, + "ave_i_frame_psnr": 33.586039, + "ave_i_frame_msssim": 0.939825, + "ave_i_frame_psnr_y": 31.359855, + "ave_i_frame_psnr_u": 39.615168, + "ave_i_frame_psnr_v": 40.914011, + "ave_i_frame_msssim_y": 0.930825, + "ave_i_frame_msssim_u": 0.962856, + "ave_i_frame_msssim_v": 0.970791, + "test_time": 8926.570544, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001418, + "ave_all_frame_psnr": 33.586039, + "ave_all_frame_msssim": 0.939825, + "ave_all_frame_psnr_y": 31.359855, + "ave_all_frame_psnr_u": 39.615168, + "ave_all_frame_psnr_v": 40.914011, + "ave_all_frame_msssim_y": 0.930825, + "ave_all_frame_msssim_u": 0.962856, + "ave_all_frame_msssim_v": 0.970791, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000887, + "ave_i_frame_psnr": 32.314815, + "ave_i_frame_msssim": 0.920176, + "ave_i_frame_psnr_y": 30.003748, + "ave_i_frame_psnr_u": 38.656236, + "ave_i_frame_psnr_v": 39.839796, + "ave_i_frame_msssim_y": 0.907251, + "ave_i_frame_msssim_u": 0.953813, + "ave_i_frame_msssim_v": 0.964094, + "test_time": 6687.421905, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000887, + "ave_all_frame_psnr": 32.314815, + "ave_all_frame_msssim": 0.920176, + "ave_all_frame_psnr_y": 30.003748, + "ave_all_frame_psnr_u": 38.656236, + "ave_all_frame_psnr_v": 39.839796, + "ave_all_frame_msssim_y": 0.907251, + "ave_all_frame_msssim_u": 0.953813, + "ave_all_frame_msssim_v": 0.964094, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000563, + "ave_i_frame_psnr": 30.983054, + "ave_i_frame_msssim": 0.896168, + "ave_i_frame_psnr_y": 28.645223, + "ave_i_frame_psnr_u": 37.435762, + "ave_i_frame_psnr_v": 38.557337, + "ave_i_frame_msssim_y": 0.878713, + "ave_i_frame_msssim_u": 0.942443, + "ave_i_frame_msssim_v": 0.954623, + "test_time": 5299.581438, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000563, + "ave_all_frame_psnr": 30.983054, + "ave_all_frame_msssim": 0.896168, + "ave_all_frame_psnr_y": 28.645223, + "ave_all_frame_psnr_u": 37.435762, + "ave_all_frame_psnr_v": 38.557337, + "ave_all_frame_msssim_y": 0.878713, + "ave_all_frame_msssim_u": 0.942443, + "ave_all_frame_msssim_v": 0.954623, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC12_1920x1080_30.yuv" + } + }, + "videoSRC13_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.276929, + "ave_i_frame_psnr": 41.514345, + "ave_i_frame_msssim": 0.994707, + "ave_i_frame_psnr_y": 39.837177, + "ave_i_frame_psnr_u": 46.031691, + "ave_i_frame_psnr_v": 47.060009, + "ave_i_frame_msssim_y": 0.995217, + "ave_i_frame_msssim_u": 0.992640, + "ave_i_frame_msssim_v": 0.993714, + "test_time": 91416.468179, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.276929, + "ave_all_frame_psnr": 41.514345, + "ave_all_frame_msssim": 0.994707, + "ave_all_frame_psnr_y": 39.837177, + "ave_all_frame_psnr_u": 46.031691, + "ave_all_frame_psnr_v": 47.060009, + "ave_all_frame_msssim_y": 0.995217, + "ave_all_frame_msssim_u": 0.992640, + "ave_all_frame_msssim_v": 0.993714, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.091846, + "ave_i_frame_psnr": 39.337109, + "ave_i_frame_msssim": 0.992945, + "ave_i_frame_psnr_y": 37.115399, + "ave_i_frame_psnr_u": 45.433563, + "ave_i_frame_psnr_v": 46.570915, + "ave_i_frame_msssim_y": 0.993255, + "ave_i_frame_msssim_u": 0.991267, + "ave_i_frame_msssim_v": 0.992764, + "test_time": 63548.615421, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.091846, + "ave_all_frame_psnr": 39.337109, + "ave_all_frame_msssim": 0.992945, + "ave_all_frame_psnr_y": 37.115399, + "ave_all_frame_psnr_u": 45.433563, + "ave_all_frame_psnr_v": 46.570915, + "ave_all_frame_msssim_y": 0.993255, + "ave_all_frame_msssim_u": 0.991267, + "ave_all_frame_msssim_v": 0.992764, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.030702, + "ave_i_frame_psnr": 37.962280, + "ave_i_frame_msssim": 0.990939, + "ave_i_frame_psnr_y": 35.475919, + "ave_i_frame_psnr_u": 44.796530, + "ave_i_frame_psnr_v": 46.046198, + "ave_i_frame_msssim_y": 0.991043, + "ave_i_frame_msssim_u": 0.989623, + "ave_i_frame_msssim_v": 0.991630, + "test_time": 30081.082496, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.030702, + "ave_all_frame_psnr": 37.962280, + "ave_all_frame_msssim": 0.990939, + "ave_all_frame_psnr_y": 35.475919, + "ave_all_frame_psnr_u": 44.796530, + "ave_all_frame_psnr_v": 46.046198, + "ave_all_frame_msssim_y": 0.991043, + "ave_all_frame_msssim_u": 0.989623, + "ave_all_frame_msssim_v": 0.991630, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012747, + "ave_i_frame_psnr": 36.848355, + "ave_i_frame_msssim": 0.988241, + "ave_i_frame_psnr_y": 34.196426, + "ave_i_frame_psnr_u": 44.135155, + "ave_i_frame_psnr_v": 45.473124, + "ave_i_frame_msssim_y": 0.988056, + "ave_i_frame_msssim_u": 0.987420, + "ave_i_frame_msssim_v": 0.990171, + "test_time": 17455.216629, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012747, + "ave_all_frame_psnr": 36.848355, + "ave_all_frame_msssim": 0.988241, + "ave_all_frame_psnr_y": 34.196426, + "ave_all_frame_psnr_u": 44.135155, + "ave_all_frame_psnr_v": 45.473124, + "ave_all_frame_msssim_y": 0.988056, + "ave_all_frame_msssim_u": 0.987420, + "ave_all_frame_msssim_v": 0.990171, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006347, + "ave_i_frame_psnr": 35.692274, + "ave_i_frame_msssim": 0.984308, + "ave_i_frame_psnr_y": 32.835618, + "ave_i_frame_psnr_u": 43.563697, + "ave_i_frame_psnr_v": 44.960786, + "ave_i_frame_msssim_y": 0.983472, + "ave_i_frame_msssim_u": 0.984895, + "ave_i_frame_msssim_v": 0.988743, + "test_time": 11672.736056, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006347, + "ave_all_frame_psnr": 35.692274, + "ave_all_frame_msssim": 0.984308, + "ave_all_frame_psnr_y": 32.835618, + "ave_all_frame_psnr_u": 43.563697, + "ave_all_frame_psnr_v": 44.960786, + "ave_all_frame_msssim_y": 0.983472, + "ave_all_frame_msssim_u": 0.984895, + "ave_all_frame_msssim_v": 0.988743, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003464, + "ave_i_frame_psnr": 34.155870, + "ave_i_frame_msssim": 0.977565, + "ave_i_frame_psnr_y": 31.351104, + "ave_i_frame_psnr_u": 41.916547, + "ave_i_frame_psnr_v": 43.223789, + "ave_i_frame_msssim_y": 0.976566, + "ave_i_frame_msssim_u": 0.978069, + "ave_i_frame_msssim_v": 0.983049, + "test_time": 9105.429956, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003464, + "ave_all_frame_psnr": 34.155870, + "ave_all_frame_msssim": 0.977565, + "ave_all_frame_psnr_y": 31.351104, + "ave_all_frame_psnr_u": 41.916547, + "ave_all_frame_psnr_v": 43.223789, + "ave_all_frame_msssim_y": 0.976566, + "ave_all_frame_msssim_u": 0.978069, + "ave_all_frame_msssim_v": 0.983049, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002062, + "ave_i_frame_psnr": 32.859286, + "ave_i_frame_msssim": 0.969135, + "ave_i_frame_psnr_y": 29.812321, + "ave_i_frame_psnr_u": 41.214423, + "ave_i_frame_psnr_v": 42.785942, + "ave_i_frame_msssim_y": 0.966217, + "ave_i_frame_msssim_u": 0.974638, + "ave_i_frame_msssim_v": 0.981141, + "test_time": 7364.730946, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002062, + "ave_all_frame_psnr": 32.859286, + "ave_all_frame_msssim": 0.969135, + "ave_all_frame_psnr_y": 29.812321, + "ave_all_frame_psnr_u": 41.214423, + "ave_all_frame_psnr_v": 42.785942, + "ave_all_frame_msssim_y": 0.966217, + "ave_all_frame_msssim_u": 0.974638, + "ave_all_frame_msssim_v": 0.981141, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001274, + "ave_i_frame_psnr": 31.580353, + "ave_i_frame_msssim": 0.957329, + "ave_i_frame_psnr_y": 28.166360, + "ave_i_frame_psnr_u": 41.088235, + "ave_i_frame_psnr_v": 42.556427, + "ave_i_frame_msssim_y": 0.950861, + "ave_i_frame_msssim_u": 0.973311, + "ave_i_frame_msssim_v": 0.980152, + "test_time": 6170.718237, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001274, + "ave_all_frame_psnr": 31.580353, + "ave_all_frame_msssim": 0.957329, + "ave_all_frame_psnr_y": 28.166360, + "ave_all_frame_psnr_u": 41.088235, + "ave_all_frame_psnr_v": 42.556427, + "ave_all_frame_msssim_y": 0.950861, + "ave_all_frame_msssim_u": 0.973311, + "ave_all_frame_msssim_v": 0.980152, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000798, + "ave_i_frame_psnr": 30.168760, + "ave_i_frame_msssim": 0.940229, + "ave_i_frame_psnr_y": 26.503440, + "ave_i_frame_psnr_u": 40.425831, + "ave_i_frame_psnr_v": 41.903609, + "ave_i_frame_msssim_y": 0.929278, + "ave_i_frame_msssim_u": 0.968524, + "ave_i_frame_msssim_v": 0.977636, + "test_time": 5382.159330, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000798, + "ave_all_frame_psnr": 30.168760, + "ave_all_frame_msssim": 0.940229, + "ave_all_frame_psnr_y": 26.503440, + "ave_all_frame_psnr_u": 40.425831, + "ave_all_frame_psnr_v": 41.903609, + "ave_all_frame_msssim_y": 0.929278, + "ave_all_frame_msssim_u": 0.968524, + "ave_all_frame_msssim_v": 0.977636, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000500, + "ave_i_frame_psnr": 28.773252, + "ave_i_frame_msssim": 0.919733, + "ave_i_frame_psnr_y": 24.884173, + "ave_i_frame_psnr_u": 39.773868, + "ave_i_frame_psnr_v": 41.107106, + "ave_i_frame_msssim_y": 0.902675, + "ave_i_frame_msssim_u": 0.966207, + "ave_i_frame_msssim_v": 0.975608, + "test_time": 4885.926169, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000500, + "ave_all_frame_psnr": 28.773252, + "ave_all_frame_msssim": 0.919733, + "ave_all_frame_psnr_y": 24.884173, + "ave_all_frame_psnr_u": 39.773868, + "ave_all_frame_psnr_v": 41.107106, + "ave_all_frame_msssim_y": 0.902675, + "ave_all_frame_msssim_u": 0.966207, + "ave_all_frame_msssim_v": 0.975608, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC13_1920x1080_30.yuv" + } + }, + "videoSRC14_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.097621, + "ave_i_frame_psnr": 42.801071, + "ave_i_frame_msssim": 0.992993, + "ave_i_frame_psnr_y": 41.896881, + "ave_i_frame_psnr_u": 46.113503, + "ave_i_frame_psnr_v": 44.913777, + "ave_i_frame_msssim_y": 0.992987, + "ave_i_frame_msssim_u": 0.993409, + "ave_i_frame_msssim_v": 0.992616, + "test_time": 148065.953979, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.097621, + "ave_all_frame_psnr": 42.801071, + "ave_all_frame_msssim": 0.992993, + "ave_all_frame_psnr_y": 41.896881, + "ave_all_frame_psnr_u": 46.113503, + "ave_all_frame_psnr_v": 44.913777, + "ave_all_frame_msssim_y": 0.992987, + "ave_all_frame_msssim_u": 0.993409, + "ave_all_frame_msssim_v": 0.992616, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.061668, + "ave_i_frame_psnr": 41.465436, + "ave_i_frame_msssim": 0.989994, + "ave_i_frame_psnr_y": 40.526954, + "ave_i_frame_psnr_u": 45.004972, + "ave_i_frame_psnr_v": 43.556791, + "ave_i_frame_msssim_y": 0.989968, + "ave_i_frame_msssim_u": 0.990902, + "ave_i_frame_msssim_v": 0.989240, + "test_time": 109066.581211, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.061668, + "ave_all_frame_psnr": 41.465436, + "ave_all_frame_msssim": 0.989994, + "ave_all_frame_psnr_y": 40.526954, + "ave_all_frame_psnr_u": 45.004972, + "ave_all_frame_psnr_v": 43.556791, + "ave_all_frame_msssim_y": 0.989968, + "ave_all_frame_msssim_u": 0.990902, + "ave_all_frame_msssim_v": 0.989240, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.040220, + "ave_i_frame_psnr": 39.983468, + "ave_i_frame_msssim": 0.985446, + "ave_i_frame_psnr_y": 38.961844, + "ave_i_frame_psnr_u": 43.885106, + "ave_i_frame_psnr_v": 42.211573, + "ave_i_frame_msssim_y": 0.985209, + "ave_i_frame_msssim_u": 0.987663, + "ave_i_frame_msssim_v": 0.984653, + "test_time": 80714.783387, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.040220, + "ave_all_frame_psnr": 39.983468, + "ave_all_frame_msssim": 0.985446, + "ave_all_frame_psnr_y": 38.961844, + "ave_all_frame_psnr_u": 43.885106, + "ave_all_frame_psnr_v": 42.211573, + "ave_all_frame_msssim_y": 0.985209, + "ave_all_frame_msssim_u": 0.987663, + "ave_all_frame_msssim_v": 0.984653, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.026609, + "ave_i_frame_psnr": 38.437271, + "ave_i_frame_msssim": 0.978815, + "ave_i_frame_psnr_y": 37.232438, + "ave_i_frame_psnr_u": 42.948772, + "ave_i_frame_psnr_v": 41.154762, + "ave_i_frame_msssim_y": 0.977758, + "ave_i_frame_msssim_u": 0.984160, + "ave_i_frame_msssim_v": 0.979812, + "test_time": 61448.967420, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.026609, + "ave_all_frame_psnr": 38.437271, + "ave_all_frame_msssim": 0.978815, + "ave_all_frame_psnr_y": 37.232438, + "ave_all_frame_psnr_u": 42.948772, + "ave_all_frame_psnr_v": 41.154762, + "ave_all_frame_msssim_y": 0.977758, + "ave_all_frame_msssim_u": 0.984160, + "ave_all_frame_msssim_v": 0.979812, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.018644, + "ave_i_frame_psnr": 37.036116, + "ave_i_frame_msssim": 0.970521, + "ave_i_frame_psnr_y": 35.718879, + "ave_i_frame_psnr_u": 41.983873, + "ave_i_frame_psnr_v": 39.991784, + "ave_i_frame_msssim_y": 0.968584, + "ave_i_frame_msssim_u": 0.979759, + "ave_i_frame_msssim_v": 0.972906, + "test_time": 48735.906427, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.018644, + "ave_all_frame_psnr": 37.036116, + "ave_all_frame_msssim": 0.970521, + "ave_all_frame_psnr_y": 35.718879, + "ave_all_frame_psnr_u": 41.983873, + "ave_all_frame_psnr_v": 39.991784, + "ave_all_frame_msssim_y": 0.968584, + "ave_all_frame_msssim_u": 0.979759, + "ave_all_frame_msssim_v": 0.972906, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013062, + "ave_i_frame_psnr": 35.624938, + "ave_i_frame_msssim": 0.959397, + "ave_i_frame_psnr_y": 34.133266, + "ave_i_frame_psnr_u": 41.090127, + "ave_i_frame_psnr_v": 39.109784, + "ave_i_frame_msssim_y": 0.955671, + "ave_i_frame_msssim_u": 0.974436, + "ave_i_frame_msssim_v": 0.966716, + "test_time": 38591.025502, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013062, + "ave_all_frame_psnr": 35.624938, + "ave_all_frame_msssim": 0.959397, + "ave_all_frame_psnr_y": 34.133266, + "ave_all_frame_psnr_u": 41.090127, + "ave_all_frame_psnr_v": 39.109784, + "ave_all_frame_msssim_y": 0.955671, + "ave_all_frame_msssim_u": 0.974436, + "ave_all_frame_msssim_v": 0.966716, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009005, + "ave_i_frame_psnr": 34.186327, + "ave_i_frame_msssim": 0.944264, + "ave_i_frame_psnr_y": 32.522317, + "ave_i_frame_psnr_u": 40.263127, + "ave_i_frame_psnr_v": 38.093589, + "ave_i_frame_msssim_y": 0.937925, + "ave_i_frame_msssim_u": 0.968617, + "ave_i_frame_msssim_v": 0.957943, + "test_time": 28820.050653, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009005, + "ave_all_frame_psnr": 34.186327, + "ave_all_frame_msssim": 0.944264, + "ave_all_frame_psnr_y": 32.522317, + "ave_all_frame_psnr_u": 40.263127, + "ave_all_frame_psnr_v": 38.093589, + "ave_all_frame_msssim_y": 0.937925, + "ave_all_frame_msssim_u": 0.968617, + "ave_all_frame_msssim_v": 0.957943, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006175, + "ave_i_frame_psnr": 32.747837, + "ave_i_frame_msssim": 0.924660, + "ave_i_frame_psnr_y": 30.887175, + "ave_i_frame_psnr_u": 39.529479, + "ave_i_frame_psnr_v": 37.130173, + "ave_i_frame_msssim_y": 0.914407, + "ave_i_frame_msssim_u": 0.962896, + "ave_i_frame_msssim_v": 0.947937, + "test_time": 22237.945809, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006175, + "ave_all_frame_psnr": 32.747837, + "ave_all_frame_msssim": 0.924660, + "ave_all_frame_psnr_y": 30.887175, + "ave_all_frame_psnr_u": 39.529479, + "ave_all_frame_psnr_v": 37.130173, + "ave_all_frame_msssim_y": 0.914407, + "ave_all_frame_msssim_u": 0.962896, + "ave_all_frame_msssim_v": 0.947937, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004151, + "ave_i_frame_psnr": 31.243454, + "ave_i_frame_msssim": 0.899686, + "ave_i_frame_psnr_y": 29.276757, + "ave_i_frame_psnr_u": 38.421735, + "ave_i_frame_psnr_v": 35.865352, + "ave_i_frame_msssim_y": 0.885520, + "ave_i_frame_msssim_u": 0.952961, + "ave_i_frame_msssim_v": 0.931408, + "test_time": 16174.900143, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004151, + "ave_all_frame_psnr": 31.243454, + "ave_all_frame_msssim": 0.899686, + "ave_all_frame_psnr_y": 29.276757, + "ave_all_frame_psnr_u": 38.421735, + "ave_all_frame_psnr_v": 35.865352, + "ave_all_frame_msssim_y": 0.885520, + "ave_all_frame_msssim_u": 0.952961, + "ave_all_frame_msssim_v": 0.931408, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002757, + "ave_i_frame_psnr": 29.736944, + "ave_i_frame_msssim": 0.867975, + "ave_i_frame_psnr_y": 27.653322, + "ave_i_frame_psnr_u": 37.375338, + "ave_i_frame_psnr_v": 34.600281, + "ave_i_frame_msssim_y": 0.848698, + "ave_i_frame_msssim_u": 0.941316, + "ave_i_frame_msssim_v": 0.910294, + "test_time": 10382.552479, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002757, + "ave_all_frame_psnr": 29.736944, + "ave_all_frame_msssim": 0.867975, + "ave_all_frame_psnr_y": 27.653322, + "ave_all_frame_psnr_u": 37.375338, + "ave_all_frame_psnr_v": 34.600281, + "ave_all_frame_msssim_y": 0.848698, + "ave_all_frame_msssim_u": 0.941316, + "ave_all_frame_msssim_v": 0.910294, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC14_1920x1080_30.yuv" + } + }, + "videoSRC15_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.060228, + "ave_i_frame_psnr": 40.436820, + "ave_i_frame_msssim": 0.991086, + "ave_i_frame_psnr_y": 39.514511, + "ave_i_frame_psnr_u": 41.954718, + "ave_i_frame_psnr_v": 44.452773, + "ave_i_frame_msssim_y": 0.991608, + "ave_i_frame_msssim_u": 0.987239, + "ave_i_frame_msssim_v": 0.991796, + "test_time": 96150.658753, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.060228, + "ave_all_frame_psnr": 40.436820, + "ave_all_frame_msssim": 0.991086, + "ave_all_frame_psnr_y": 39.514511, + "ave_all_frame_psnr_u": 41.954718, + "ave_all_frame_psnr_v": 44.452773, + "ave_all_frame_msssim_y": 0.991608, + "ave_all_frame_msssim_u": 0.987239, + "ave_all_frame_msssim_v": 0.991796, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.018122, + "ave_i_frame_psnr": 39.533128, + "ave_i_frame_msssim": 0.988782, + "ave_i_frame_psnr_y": 38.551262, + "ave_i_frame_psnr_u": 41.327769, + "ave_i_frame_psnr_v": 43.629683, + "ave_i_frame_msssim_y": 0.989286, + "ave_i_frame_msssim_u": 0.984756, + "ave_i_frame_msssim_v": 0.989781, + "test_time": 40209.036364, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.018122, + "ave_all_frame_psnr": 39.533128, + "ave_all_frame_msssim": 0.988782, + "ave_all_frame_psnr_y": 38.551262, + "ave_all_frame_psnr_u": 41.327769, + "ave_all_frame_psnr_v": 43.629683, + "ave_all_frame_msssim_y": 0.989286, + "ave_all_frame_msssim_u": 0.984756, + "ave_all_frame_msssim_v": 0.989781, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008141, + "ave_i_frame_psnr": 38.548468, + "ave_i_frame_msssim": 0.985682, + "ave_i_frame_psnr_y": 37.446156, + "ave_i_frame_psnr_u": 40.839556, + "ave_i_frame_psnr_v": 42.871252, + "ave_i_frame_msssim_y": 0.985826, + "ave_i_frame_msssim_u": 0.982837, + "ave_i_frame_msssim_v": 0.987661, + "test_time": 26189.045941, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008141, + "ave_all_frame_psnr": 38.548468, + "ave_all_frame_msssim": 0.985682, + "ave_all_frame_psnr_y": 37.446156, + "ave_all_frame_psnr_u": 40.839556, + "ave_all_frame_psnr_v": 42.871252, + "ave_all_frame_msssim_y": 0.985826, + "ave_all_frame_msssim_u": 0.982837, + "ave_all_frame_msssim_v": 0.987661, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004763, + "ave_i_frame_psnr": 37.512187, + "ave_i_frame_msssim": 0.981325, + "ave_i_frame_psnr_y": 36.304867, + "ave_i_frame_psnr_u": 40.249478, + "ave_i_frame_psnr_v": 42.018818, + "ave_i_frame_msssim_y": 0.980977, + "ave_i_frame_msssim_u": 0.980212, + "ave_i_frame_msssim_v": 0.984523, + "test_time": 19710.589620, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004763, + "ave_all_frame_psnr": 37.512187, + "ave_all_frame_msssim": 0.981325, + "ave_all_frame_psnr_y": 36.304867, + "ave_all_frame_psnr_u": 40.249478, + "ave_all_frame_psnr_v": 42.018818, + "ave_all_frame_msssim_y": 0.980977, + "ave_all_frame_msssim_u": 0.980212, + "ave_all_frame_msssim_v": 0.984523, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003201, + "ave_i_frame_psnr": 36.393857, + "ave_i_frame_msssim": 0.975114, + "ave_i_frame_psnr_y": 35.096587, + "ave_i_frame_psnr_u": 39.533700, + "ave_i_frame_psnr_v": 41.037636, + "ave_i_frame_msssim_y": 0.974101, + "ave_i_frame_msssim_u": 0.976183, + "ave_i_frame_msssim_v": 0.980128, + "test_time": 15749.053322, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003201, + "ave_all_frame_psnr": 36.393857, + "ave_all_frame_msssim": 0.975114, + "ave_all_frame_psnr_y": 35.096587, + "ave_all_frame_psnr_u": 39.533700, + "ave_all_frame_psnr_v": 41.037636, + "ave_all_frame_msssim_y": 0.974101, + "ave_all_frame_msssim_u": 0.976183, + "ave_all_frame_msssim_v": 0.980128, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002165, + "ave_i_frame_psnr": 35.130157, + "ave_i_frame_msssim": 0.965214, + "ave_i_frame_psnr_y": 33.705250, + "ave_i_frame_psnr_u": 38.702475, + "ave_i_frame_psnr_v": 40.107276, + "ave_i_frame_msssim_y": 0.962627, + "ave_i_frame_msssim_u": 0.971285, + "ave_i_frame_msssim_v": 0.974662, + "test_time": 12877.779374, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002165, + "ave_all_frame_psnr": 35.130157, + "ave_all_frame_msssim": 0.965214, + "ave_all_frame_psnr_y": 33.705250, + "ave_all_frame_psnr_u": 38.702475, + "ave_all_frame_psnr_v": 40.107276, + "ave_all_frame_msssim_y": 0.962627, + "ave_all_frame_msssim_u": 0.971285, + "ave_all_frame_msssim_v": 0.974662, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001473, + "ave_i_frame_psnr": 33.861998, + "ave_i_frame_msssim": 0.950051, + "ave_i_frame_psnr_y": 32.227825, + "ave_i_frame_psnr_u": 38.139625, + "ave_i_frame_psnr_v": 39.389405, + "ave_i_frame_msssim_y": 0.944137, + "ave_i_frame_msssim_u": 0.966447, + "ave_i_frame_msssim_v": 0.969138, + "test_time": 10559.284901, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001473, + "ave_all_frame_psnr": 33.861998, + "ave_all_frame_msssim": 0.950051, + "ave_all_frame_psnr_y": 32.227825, + "ave_all_frame_psnr_u": 38.139625, + "ave_all_frame_psnr_v": 39.389405, + "ave_all_frame_msssim_y": 0.944137, + "ave_all_frame_msssim_u": 0.966447, + "ave_all_frame_msssim_v": 0.969138, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001011, + "ave_i_frame_psnr": 32.622750, + "ave_i_frame_msssim": 0.928912, + "ave_i_frame_psnr_y": 30.738838, + "ave_i_frame_psnr_u": 37.645024, + "ave_i_frame_psnr_v": 38.903948, + "ave_i_frame_msssim_y": 0.917342, + "ave_i_frame_msssim_u": 0.961862, + "ave_i_frame_msssim_v": 0.965383, + "test_time": 8758.368118, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001011, + "ave_all_frame_psnr": 32.622750, + "ave_all_frame_msssim": 0.928912, + "ave_all_frame_psnr_y": 30.738838, + "ave_all_frame_psnr_u": 37.645024, + "ave_all_frame_psnr_v": 38.903948, + "ave_all_frame_msssim_y": 0.917342, + "ave_all_frame_msssim_u": 0.961862, + "ave_all_frame_msssim_v": 0.965383, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000697, + "ave_i_frame_psnr": 31.283122, + "ave_i_frame_msssim": 0.897508, + "ave_i_frame_psnr_y": 29.287271, + "ave_i_frame_psnr_u": 36.665430, + "ave_i_frame_psnr_v": 37.875921, + "ave_i_frame_msssim_y": 0.878998, + "ave_i_frame_msssim_u": 0.950408, + "ave_i_frame_msssim_v": 0.955670, + "test_time": 7292.483102, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000697, + "ave_all_frame_psnr": 31.283122, + "ave_all_frame_msssim": 0.897508, + "ave_all_frame_psnr_y": 29.287271, + "ave_all_frame_psnr_u": 36.665430, + "ave_all_frame_psnr_v": 37.875921, + "ave_all_frame_msssim_y": 0.878998, + "ave_all_frame_msssim_u": 0.950408, + "ave_all_frame_msssim_v": 0.955670, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000496, + "ave_i_frame_psnr": 29.988365, + "ave_i_frame_msssim": 0.856457, + "ave_i_frame_psnr_y": 27.886618, + "ave_i_frame_psnr_u": 35.598145, + "ave_i_frame_psnr_v": 36.989065, + "ave_i_frame_msssim_y": 0.828810, + "ave_i_frame_msssim_u": 0.935165, + "ave_i_frame_msssim_v": 0.943630, + "test_time": 5799.923993, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000496, + "ave_all_frame_psnr": 29.988365, + "ave_all_frame_msssim": 0.856457, + "ave_all_frame_psnr_y": 27.886618, + "ave_all_frame_psnr_u": 35.598145, + "ave_all_frame_psnr_v": 36.989065, + "ave_all_frame_msssim_y": 0.828810, + "ave_all_frame_msssim_u": 0.935165, + "ave_all_frame_msssim_v": 0.943630, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC15_1920x1080_30.yuv" + } + }, + "videoSRC16_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.019684, + "ave_i_frame_psnr": 44.313164, + "ave_i_frame_msssim": 0.992836, + "ave_i_frame_psnr_y": 43.396352, + "ave_i_frame_psnr_u": 46.303050, + "ave_i_frame_psnr_v": 47.824149, + "ave_i_frame_msssim_y": 0.992208, + "ave_i_frame_msssim_u": 0.994395, + "ave_i_frame_msssim_v": 0.995041, + "test_time": 58884.049128, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.019684, + "ave_all_frame_psnr": 44.313164, + "ave_all_frame_msssim": 0.992836, + "ave_all_frame_psnr_y": 43.396352, + "ave_all_frame_psnr_u": 46.303050, + "ave_all_frame_psnr_v": 47.824149, + "ave_all_frame_msssim_y": 0.992208, + "ave_all_frame_msssim_u": 0.994395, + "ave_all_frame_msssim_v": 0.995041, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011931, + "ave_i_frame_psnr": 43.647838, + "ave_i_frame_msssim": 0.991303, + "ave_i_frame_psnr_y": 42.779992, + "ave_i_frame_psnr_u": 45.417210, + "ave_i_frame_psnr_v": 47.085545, + "ave_i_frame_msssim_y": 0.990655, + "ave_i_frame_msssim_u": 0.992818, + "ave_i_frame_msssim_v": 0.993676, + "test_time": 41321.189653, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011931, + "ave_all_frame_psnr": 43.647838, + "ave_all_frame_msssim": 0.991303, + "ave_all_frame_psnr_y": 42.779992, + "ave_all_frame_psnr_u": 45.417210, + "ave_all_frame_psnr_v": 47.085545, + "ave_all_frame_msssim_y": 0.990655, + "ave_all_frame_msssim_u": 0.992818, + "ave_all_frame_msssim_v": 0.993676, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007388, + "ave_i_frame_psnr": 42.789507, + "ave_i_frame_msssim": 0.988951, + "ave_i_frame_psnr_y": 41.955093, + "ave_i_frame_psnr_u": 44.380943, + "ave_i_frame_psnr_v": 46.204556, + "ave_i_frame_msssim_y": 0.988223, + "ave_i_frame_msssim_u": 0.990524, + "ave_i_frame_msssim_v": 0.991741, + "test_time": 28475.165564, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007388, + "ave_all_frame_psnr": 42.789507, + "ave_all_frame_msssim": 0.988951, + "ave_all_frame_psnr_y": 41.955093, + "ave_all_frame_psnr_u": 44.380943, + "ave_all_frame_psnr_v": 46.204556, + "ave_all_frame_msssim_y": 0.988223, + "ave_all_frame_msssim_u": 0.990524, + "ave_all_frame_msssim_v": 0.991741, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004720, + "ave_i_frame_psnr": 41.807056, + "ave_i_frame_msssim": 0.985660, + "ave_i_frame_psnr_y": 40.950757, + "ave_i_frame_psnr_u": 43.418659, + "ave_i_frame_psnr_v": 45.333252, + "ave_i_frame_msssim_y": 0.984720, + "ave_i_frame_msssim_u": 0.987573, + "ave_i_frame_msssim_v": 0.989389, + "test_time": 20031.682379, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004720, + "ave_all_frame_psnr": 41.807056, + "ave_all_frame_msssim": 0.985660, + "ave_all_frame_psnr_y": 40.950757, + "ave_all_frame_psnr_u": 43.418659, + "ave_all_frame_psnr_v": 45.333252, + "ave_all_frame_msssim_y": 0.984720, + "ave_all_frame_msssim_u": 0.987573, + "ave_all_frame_msssim_v": 0.989389, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003166, + "ave_i_frame_psnr": 40.746051, + "ave_i_frame_msssim": 0.981174, + "ave_i_frame_psnr_y": 39.901118, + "ave_i_frame_psnr_u": 42.314003, + "ave_i_frame_psnr_v": 44.247699, + "ave_i_frame_msssim_y": 0.980072, + "ave_i_frame_msssim_u": 0.983334, + "ave_i_frame_msssim_v": 0.985630, + "test_time": 14900.821085, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003166, + "ave_all_frame_psnr": 40.746051, + "ave_all_frame_msssim": 0.981174, + "ave_all_frame_psnr_y": 39.901118, + "ave_all_frame_psnr_u": 42.314003, + "ave_all_frame_psnr_v": 44.247699, + "ave_all_frame_msssim_y": 0.980072, + "ave_all_frame_msssim_u": 0.983334, + "ave_all_frame_msssim_v": 0.985630, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002152, + "ave_i_frame_psnr": 39.705885, + "ave_i_frame_msssim": 0.975635, + "ave_i_frame_psnr_y": 38.736028, + "ave_i_frame_psnr_u": 41.415618, + "ave_i_frame_psnr_v": 43.815289, + "ave_i_frame_msssim_y": 0.973573, + "ave_i_frame_msssim_u": 0.979476, + "ave_i_frame_msssim_v": 0.984168, + "test_time": 11337.408271, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002152, + "ave_all_frame_psnr": 39.705885, + "ave_all_frame_msssim": 0.975635, + "ave_all_frame_psnr_y": 38.736028, + "ave_all_frame_psnr_u": 41.415618, + "ave_all_frame_psnr_v": 43.815289, + "ave_all_frame_msssim_y": 0.973573, + "ave_all_frame_msssim_u": 0.979476, + "ave_all_frame_msssim_v": 0.984168, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001433, + "ave_i_frame_psnr": 38.557733, + "ave_i_frame_msssim": 0.967846, + "ave_i_frame_psnr_y": 37.477739, + "ave_i_frame_psnr_u": 40.522094, + "ave_i_frame_psnr_v": 43.073341, + "ave_i_frame_msssim_y": 0.964513, + "ave_i_frame_msssim_u": 0.974672, + "ave_i_frame_msssim_v": 0.981015, + "test_time": 8613.118054, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001433, + "ave_all_frame_psnr": 38.557733, + "ave_all_frame_msssim": 0.967846, + "ave_all_frame_psnr_y": 37.477739, + "ave_all_frame_psnr_u": 40.522094, + "ave_all_frame_psnr_v": 43.073341, + "ave_all_frame_msssim_y": 0.964513, + "ave_all_frame_msssim_u": 0.974672, + "ave_all_frame_msssim_v": 0.981015, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000954, + "ave_i_frame_psnr": 37.332201, + "ave_i_frame_msssim": 0.957146, + "ave_i_frame_psnr_y": 36.108382, + "ave_i_frame_psnr_u": 39.659021, + "ave_i_frame_psnr_v": 42.348294, + "ave_i_frame_msssim_y": 0.951813, + "ave_i_frame_msssim_u": 0.968765, + "ave_i_frame_msssim_v": 0.977527, + "test_time": 6494.451940, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000954, + "ave_all_frame_psnr": 37.332201, + "ave_all_frame_msssim": 0.957146, + "ave_all_frame_psnr_y": 36.108382, + "ave_all_frame_psnr_u": 39.659021, + "ave_all_frame_psnr_v": 42.348294, + "ave_all_frame_msssim_y": 0.951813, + "ave_all_frame_msssim_u": 0.968765, + "ave_all_frame_msssim_v": 0.977527, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000631, + "ave_i_frame_psnr": 36.010078, + "ave_i_frame_msssim": 0.943446, + "ave_i_frame_psnr_y": 34.756126, + "ave_i_frame_psnr_u": 38.307400, + "ave_i_frame_psnr_v": 41.236465, + "ave_i_frame_msssim_y": 0.936439, + "ave_i_frame_msssim_u": 0.957703, + "ave_i_frame_msssim_v": 0.971237, + "test_time": 5026.613278, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000631, + "ave_all_frame_psnr": 36.010078, + "ave_all_frame_msssim": 0.943446, + "ave_all_frame_psnr_y": 34.756126, + "ave_all_frame_psnr_u": 38.307400, + "ave_all_frame_psnr_v": 41.236465, + "ave_all_frame_msssim_y": 0.936439, + "ave_all_frame_msssim_u": 0.957703, + "ave_all_frame_msssim_v": 0.971237, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000421, + "ave_i_frame_psnr": 34.615790, + "ave_i_frame_msssim": 0.925035, + "ave_i_frame_psnr_y": 33.336531, + "ave_i_frame_psnr_u": 36.952863, + "ave_i_frame_psnr_v": 39.954273, + "ave_i_frame_msssim_y": 0.915453, + "ave_i_frame_msssim_u": 0.943070, + "ave_i_frame_msssim_v": 0.964493, + "test_time": 4150.208981, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000421, + "ave_all_frame_psnr": 34.615790, + "ave_all_frame_msssim": 0.925035, + "ave_all_frame_psnr_y": 33.336531, + "ave_all_frame_psnr_u": 36.952863, + "ave_all_frame_psnr_v": 39.954273, + "ave_all_frame_msssim_y": 0.915453, + "ave_all_frame_msssim_u": 0.943070, + "ave_all_frame_msssim_v": 0.964493, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC16_1920x1080_30.yuv" + } + }, + "videoSRC17_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.098032, + "ave_i_frame_psnr": 42.671912, + "ave_i_frame_msssim": 0.991975, + "ave_i_frame_psnr_y": 42.182084, + "ave_i_frame_psnr_u": 43.213747, + "ave_i_frame_psnr_v": 45.069043, + "ave_i_frame_msssim_y": 0.993049, + "ave_i_frame_msssim_u": 0.987279, + "ave_i_frame_msssim_v": 0.990227, + "test_time": 115926.861543, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.098032, + "ave_all_frame_psnr": 42.671912, + "ave_all_frame_msssim": 0.991975, + "ave_all_frame_psnr_y": 42.182084, + "ave_all_frame_psnr_u": 43.213747, + "ave_all_frame_psnr_v": 45.069043, + "ave_all_frame_msssim_y": 0.993049, + "ave_all_frame_msssim_u": 0.987279, + "ave_all_frame_msssim_v": 0.990227, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.062093, + "ave_i_frame_psnr": 41.558054, + "ave_i_frame_msssim": 0.988561, + "ave_i_frame_psnr_y": 41.064808, + "ave_i_frame_psnr_u": 42.148745, + "ave_i_frame_psnr_v": 43.926842, + "ave_i_frame_msssim_y": 0.990064, + "ave_i_frame_msssim_u": 0.981883, + "ave_i_frame_msssim_v": 0.986223, + "test_time": 83760.323265, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.062093, + "ave_all_frame_psnr": 41.558054, + "ave_all_frame_msssim": 0.988561, + "ave_all_frame_psnr_y": 41.064808, + "ave_all_frame_psnr_u": 42.148745, + "ave_all_frame_psnr_v": 43.926842, + "ave_all_frame_msssim_y": 0.990064, + "ave_all_frame_msssim_u": 0.981883, + "ave_all_frame_msssim_v": 0.986223, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.039599, + "ave_i_frame_psnr": 40.212965, + "ave_i_frame_msssim": 0.983142, + "ave_i_frame_psnr_y": 39.600080, + "ave_i_frame_psnr_u": 41.171497, + "ave_i_frame_psnr_v": 42.931745, + "ave_i_frame_msssim_y": 0.984632, + "ave_i_frame_msssim_u": 0.975463, + "ave_i_frame_msssim_v": 0.981885, + "test_time": 61458.129827, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.039599, + "ave_all_frame_psnr": 40.212965, + "ave_all_frame_msssim": 0.983142, + "ave_all_frame_psnr_y": 39.600080, + "ave_all_frame_psnr_u": 41.171497, + "ave_all_frame_psnr_v": 42.931745, + "ave_all_frame_msssim_y": 0.984632, + "ave_all_frame_msssim_u": 0.975463, + "ave_all_frame_msssim_v": 0.981885, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.025091, + "ave_i_frame_psnr": 38.698639, + "ave_i_frame_msssim": 0.974715, + "ave_i_frame_psnr_y": 37.832501, + "ave_i_frame_psnr_u": 40.438820, + "ave_i_frame_psnr_v": 42.155290, + "ave_i_frame_msssim_y": 0.975073, + "ave_i_frame_msssim_u": 0.969597, + "ave_i_frame_msssim_v": 0.977680, + "test_time": 48286.173547, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.025091, + "ave_all_frame_psnr": 38.698639, + "ave_all_frame_msssim": 0.974715, + "ave_all_frame_psnr_y": 37.832501, + "ave_all_frame_psnr_u": 40.438820, + "ave_all_frame_psnr_v": 42.155290, + "ave_all_frame_msssim_y": 0.975073, + "ave_all_frame_msssim_u": 0.969597, + "ave_all_frame_msssim_v": 0.977680, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016855, + "ave_i_frame_psnr": 37.340058, + "ave_i_frame_msssim": 0.964146, + "ave_i_frame_psnr_y": 36.275894, + "ave_i_frame_psnr_u": 39.621074, + "ave_i_frame_psnr_v": 41.444028, + "ave_i_frame_msssim_y": 0.962999, + "ave_i_frame_msssim_u": 0.961803, + "ave_i_frame_msssim_v": 0.973365, + "test_time": 36170.547789, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016855, + "ave_all_frame_psnr": 37.340058, + "ave_all_frame_msssim": 0.964146, + "ave_all_frame_psnr_y": 36.275894, + "ave_all_frame_psnr_u": 39.621074, + "ave_all_frame_psnr_v": 41.444028, + "ave_all_frame_msssim_y": 0.962999, + "ave_all_frame_msssim_u": 0.961803, + "ave_all_frame_msssim_v": 0.973365, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011115, + "ave_i_frame_psnr": 35.930771, + "ave_i_frame_msssim": 0.949350, + "ave_i_frame_psnr_y": 34.651298, + "ave_i_frame_psnr_u": 39.020176, + "ave_i_frame_psnr_v": 40.518207, + "ave_i_frame_msssim_y": 0.945509, + "ave_i_frame_msssim_u": 0.955236, + "ave_i_frame_msssim_v": 0.966514, + "test_time": 26547.775422, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011115, + "ave_all_frame_psnr": 35.930771, + "ave_all_frame_msssim": 0.949350, + "ave_all_frame_psnr_y": 34.651298, + "ave_all_frame_psnr_u": 39.020176, + "ave_all_frame_psnr_v": 40.518207, + "ave_all_frame_msssim_y": 0.945509, + "ave_all_frame_msssim_u": 0.955236, + "ave_all_frame_msssim_v": 0.966514, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007169, + "ave_i_frame_psnr": 34.572404, + "ave_i_frame_msssim": 0.929723, + "ave_i_frame_psnr_y": 33.022178, + "ave_i_frame_psnr_u": 38.361836, + "ave_i_frame_psnr_v": 40.084326, + "ave_i_frame_msssim_y": 0.921324, + "ave_i_frame_msssim_u": 0.946842, + "ave_i_frame_msssim_v": 0.962999, + "test_time": 19217.981613, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007169, + "ave_all_frame_psnr": 34.572404, + "ave_all_frame_msssim": 0.929723, + "ave_all_frame_psnr_y": 33.022178, + "ave_all_frame_psnr_u": 38.361836, + "ave_all_frame_psnr_v": 40.084326, + "ave_all_frame_msssim_y": 0.921324, + "ave_all_frame_msssim_u": 0.946842, + "ave_all_frame_msssim_v": 0.962999, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004535, + "ave_i_frame_psnr": 33.294528, + "ave_i_frame_msssim": 0.905502, + "ave_i_frame_psnr_y": 31.467042, + "ave_i_frame_psnr_u": 37.852624, + "ave_i_frame_psnr_v": 39.701352, + "ave_i_frame_msssim_y": 0.890601, + "ave_i_frame_msssim_u": 0.940450, + "ave_i_frame_msssim_v": 0.959959, + "test_time": 14026.277945, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004535, + "ave_all_frame_psnr": 33.294528, + "ave_all_frame_msssim": 0.905502, + "ave_all_frame_psnr_y": 31.467042, + "ave_all_frame_psnr_u": 37.852624, + "ave_all_frame_psnr_v": 39.701352, + "ave_all_frame_msssim_y": 0.890601, + "ave_all_frame_msssim_u": 0.940450, + "ave_all_frame_msssim_v": 0.959959, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002796, + "ave_i_frame_psnr": 32.009838, + "ave_i_frame_msssim": 0.875391, + "ave_i_frame_psnr_y": 29.981233, + "ave_i_frame_psnr_u": 37.071584, + "ave_i_frame_psnr_v": 39.119722, + "ave_i_frame_msssim_y": 0.853079, + "ave_i_frame_msssim_u": 0.929508, + "ave_i_frame_msssim_v": 0.955143, + "test_time": 10142.476662, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002796, + "ave_all_frame_psnr": 32.009838, + "ave_all_frame_msssim": 0.875391, + "ave_all_frame_psnr_y": 29.981233, + "ave_all_frame_psnr_u": 37.071584, + "ave_all_frame_psnr_v": 39.119722, + "ave_all_frame_msssim_y": 0.853079, + "ave_all_frame_msssim_u": 0.929508, + "ave_all_frame_msssim_v": 0.955143, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001688, + "ave_i_frame_psnr": 30.767851, + "ave_i_frame_msssim": 0.840091, + "ave_i_frame_psnr_y": 28.567746, + "ave_i_frame_psnr_u": 36.245244, + "ave_i_frame_psnr_v": 38.491086, + "ave_i_frame_msssim_y": 0.808864, + "ave_i_frame_msssim_u": 0.917206, + "ave_i_frame_msssim_v": 0.950341, + "test_time": 6886.999459, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001688, + "ave_all_frame_psnr": 30.767851, + "ave_all_frame_msssim": 0.840091, + "ave_all_frame_psnr_y": 28.567746, + "ave_all_frame_psnr_u": 36.245244, + "ave_all_frame_psnr_v": 38.491086, + "ave_all_frame_msssim_y": 0.808864, + "ave_all_frame_msssim_u": 0.917206, + "ave_all_frame_msssim_v": 0.950341, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC17_1920x1080_24.yuv" + } + }, + "videoSRC18_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.057527, + "ave_i_frame_psnr": 42.859882, + "ave_i_frame_msssim": 0.995367, + "ave_i_frame_psnr_y": 42.367457, + "ave_i_frame_psnr_u": 44.213205, + "ave_i_frame_psnr_v": 44.461105, + "ave_i_frame_msssim_y": 0.995805, + "ave_i_frame_msssim_u": 0.994379, + "ave_i_frame_msssim_v": 0.993724, + "test_time": 55112.449296, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.057527, + "ave_all_frame_psnr": 42.859882, + "ave_all_frame_msssim": 0.995367, + "ave_all_frame_psnr_y": 42.367457, + "ave_all_frame_psnr_u": 44.213205, + "ave_all_frame_psnr_v": 44.461105, + "ave_all_frame_msssim_y": 0.995805, + "ave_all_frame_msssim_u": 0.994379, + "ave_all_frame_msssim_v": 0.993724, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.036264, + "ave_i_frame_psnr": 40.826763, + "ave_i_frame_msssim": 0.992378, + "ave_i_frame_psnr_y": 40.218527, + "ave_i_frame_psnr_u": 42.533047, + "ave_i_frame_psnr_v": 42.769896, + "ave_i_frame_msssim_y": 0.992894, + "ave_i_frame_msssim_u": 0.991322, + "ave_i_frame_msssim_v": 0.990336, + "test_time": 41929.396469, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.036264, + "ave_all_frame_psnr": 40.826763, + "ave_all_frame_msssim": 0.992378, + "ave_all_frame_psnr_y": 40.218527, + "ave_all_frame_psnr_u": 42.533047, + "ave_all_frame_psnr_v": 42.769896, + "ave_all_frame_msssim_y": 0.992894, + "ave_all_frame_msssim_u": 0.991322, + "ave_all_frame_msssim_v": 0.990336, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.023053, + "ave_i_frame_psnr": 38.863907, + "ave_i_frame_msssim": 0.987681, + "ave_i_frame_psnr_y": 38.111771, + "ave_i_frame_psnr_u": 40.988590, + "ave_i_frame_psnr_v": 41.252046, + "ave_i_frame_msssim_y": 0.988095, + "ave_i_frame_msssim_u": 0.987038, + "ave_i_frame_msssim_v": 0.985841, + "test_time": 32071.017099, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.023053, + "ave_all_frame_psnr": 38.863907, + "ave_all_frame_msssim": 0.987681, + "ave_all_frame_psnr_y": 38.111771, + "ave_all_frame_psnr_u": 40.988590, + "ave_all_frame_psnr_v": 41.252046, + "ave_all_frame_msssim_y": 0.988095, + "ave_all_frame_msssim_u": 0.987038, + "ave_all_frame_msssim_v": 0.985841, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014761, + "ave_i_frame_psnr": 36.980901, + "ave_i_frame_msssim": 0.980403, + "ave_i_frame_psnr_y": 36.049874, + "ave_i_frame_psnr_u": 39.685185, + "ave_i_frame_psnr_v": 39.862776, + "ave_i_frame_msssim_y": 0.980261, + "ave_i_frame_msssim_u": 0.981793, + "ave_i_frame_msssim_v": 0.979860, + "test_time": 26064.760883, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014761, + "ave_all_frame_psnr": 36.980901, + "ave_all_frame_msssim": 0.980403, + "ave_all_frame_psnr_y": 36.049874, + "ave_all_frame_psnr_u": 39.685185, + "ave_all_frame_psnr_v": 39.862776, + "ave_all_frame_msssim_y": 0.980261, + "ave_all_frame_msssim_u": 0.981793, + "ave_all_frame_msssim_v": 0.979860, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009714, + "ave_i_frame_psnr": 35.275236, + "ave_i_frame_msssim": 0.970226, + "ave_i_frame_psnr_y": 34.195475, + "ave_i_frame_psnr_u": 38.390241, + "ave_i_frame_psnr_v": 38.638796, + "ave_i_frame_msssim_y": 0.969124, + "ave_i_frame_msssim_u": 0.974559, + "ave_i_frame_msssim_v": 0.972503, + "test_time": 20525.900164, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009714, + "ave_all_frame_psnr": 35.275236, + "ave_all_frame_msssim": 0.970226, + "ave_all_frame_psnr_y": 34.195475, + "ave_all_frame_psnr_u": 38.390241, + "ave_all_frame_psnr_v": 38.638796, + "ave_all_frame_msssim_y": 0.969124, + "ave_all_frame_msssim_u": 0.974559, + "ave_all_frame_msssim_v": 0.972503, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006386, + "ave_i_frame_psnr": 33.707331, + "ave_i_frame_msssim": 0.956680, + "ave_i_frame_psnr_y": 32.405786, + "ave_i_frame_psnr_u": 37.236686, + "ave_i_frame_psnr_v": 37.987249, + "ave_i_frame_msssim_y": 0.952923, + "ave_i_frame_msssim_u": 0.968200, + "ave_i_frame_msssim_v": 0.967697, + "test_time": 16279.973842, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006386, + "ave_all_frame_psnr": 33.707331, + "ave_all_frame_msssim": 0.956680, + "ave_all_frame_psnr_y": 32.405786, + "ave_all_frame_psnr_u": 37.236686, + "ave_all_frame_psnr_v": 37.987249, + "ave_all_frame_msssim_y": 0.952923, + "ave_all_frame_msssim_u": 0.968200, + "ave_all_frame_msssim_v": 0.967697, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004099, + "ave_i_frame_psnr": 32.216232, + "ave_i_frame_msssim": 0.937775, + "ave_i_frame_psnr_y": 30.710259, + "ave_i_frame_psnr_u": 36.324310, + "ave_i_frame_psnr_v": 37.143989, + "ave_i_frame_msssim_y": 0.930398, + "ave_i_frame_msssim_u": 0.959616, + "ave_i_frame_msssim_v": 0.960200, + "test_time": 12817.076375, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004099, + "ave_all_frame_psnr": 32.216232, + "ave_all_frame_msssim": 0.937775, + "ave_all_frame_psnr_y": 30.710259, + "ave_all_frame_psnr_u": 36.324310, + "ave_all_frame_psnr_v": 37.143989, + "ave_all_frame_msssim_y": 0.930398, + "ave_all_frame_msssim_u": 0.959616, + "ave_all_frame_msssim_v": 0.960200, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002600, + "ave_i_frame_psnr": 30.826063, + "ave_i_frame_msssim": 0.914366, + "ave_i_frame_psnr_y": 29.134047, + "ave_i_frame_psnr_u": 35.445072, + "ave_i_frame_psnr_v": 36.359150, + "ave_i_frame_msssim_y": 0.902165, + "ave_i_frame_msssim_u": 0.949795, + "ave_i_frame_msssim_v": 0.952141, + "test_time": 9964.271855, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002600, + "ave_all_frame_psnr": 30.826063, + "ave_all_frame_msssim": 0.914366, + "ave_all_frame_psnr_y": 29.134047, + "ave_all_frame_psnr_u": 35.445072, + "ave_all_frame_psnr_v": 36.359150, + "ave_all_frame_msssim_y": 0.902165, + "ave_all_frame_msssim_u": 0.949795, + "ave_all_frame_msssim_v": 0.952141, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001613, + "ave_i_frame_psnr": 29.461393, + "ave_i_frame_msssim": 0.884175, + "ave_i_frame_psnr_y": 27.701136, + "ave_i_frame_psnr_u": 34.273084, + "ave_i_frame_psnr_v": 35.211247, + "ave_i_frame_msssim_y": 0.867541, + "ave_i_frame_msssim_u": 0.931549, + "ave_i_frame_msssim_v": 0.936608, + "test_time": 7583.794887, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001613, + "ave_all_frame_psnr": 29.461393, + "ave_all_frame_msssim": 0.884175, + "ave_all_frame_psnr_y": 27.701136, + "ave_all_frame_psnr_u": 34.273084, + "ave_all_frame_psnr_v": 35.211247, + "ave_all_frame_msssim_y": 0.867541, + "ave_all_frame_msssim_u": 0.931549, + "ave_all_frame_msssim_v": 0.936608, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000998, + "ave_i_frame_psnr": 28.235498, + "ave_i_frame_msssim": 0.848853, + "ave_i_frame_psnr_y": 26.443143, + "ave_i_frame_psnr_u": 33.127648, + "ave_i_frame_psnr_v": 34.097481, + "ave_i_frame_msssim_y": 0.827062, + "ave_i_frame_msssim_u": 0.910880, + "ave_i_frame_msssim_v": 0.917572, + "test_time": 5686.564836, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000998, + "ave_all_frame_psnr": 28.235498, + "ave_all_frame_msssim": 0.848853, + "ave_all_frame_psnr_y": 26.443143, + "ave_all_frame_psnr_u": 33.127648, + "ave_all_frame_psnr_v": 34.097481, + "ave_all_frame_msssim_y": 0.827062, + "ave_all_frame_msssim_u": 0.910880, + "ave_all_frame_msssim_v": 0.917572, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC18_1920x1080_25.yuv" + } + }, + "videoSRC19_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.099998, + "ave_i_frame_psnr": 43.749820, + "ave_i_frame_msssim": 0.994230, + "ave_i_frame_psnr_y": 42.818337, + "ave_i_frame_psnr_u": 46.358205, + "ave_i_frame_psnr_v": 46.730338, + "ave_i_frame_msssim_y": 0.994296, + "ave_i_frame_msssim_u": 0.993690, + "ave_i_frame_msssim_v": 0.994377, + "test_time": 115748.799413, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.099998, + "ave_all_frame_psnr": 43.749820, + "ave_all_frame_msssim": 0.994230, + "ave_all_frame_psnr_y": 42.818337, + "ave_all_frame_psnr_u": 46.358205, + "ave_all_frame_psnr_v": 46.730338, + "ave_all_frame_msssim_y": 0.994296, + "ave_all_frame_msssim_u": 0.993690, + "ave_all_frame_msssim_v": 0.994377, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.065110, + "ave_i_frame_psnr": 41.990615, + "ave_i_frame_msssim": 0.990904, + "ave_i_frame_psnr_y": 40.928287, + "ave_i_frame_psnr_u": 45.101587, + "ave_i_frame_psnr_v": 45.253618, + "ave_i_frame_msssim_y": 0.990775, + "ave_i_frame_msssim_u": 0.990983, + "ave_i_frame_msssim_v": 0.991600, + "test_time": 91556.397878, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.065110, + "ave_all_frame_psnr": 41.990615, + "ave_all_frame_msssim": 0.990904, + "ave_all_frame_psnr_y": 40.928287, + "ave_all_frame_psnr_u": 45.101587, + "ave_all_frame_psnr_v": 45.253618, + "ave_all_frame_msssim_y": 0.990775, + "ave_all_frame_msssim_u": 0.990983, + "ave_all_frame_msssim_v": 0.991600, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.042197, + "ave_i_frame_psnr": 40.206427, + "ave_i_frame_msssim": 0.985542, + "ave_i_frame_psnr_y": 38.979269, + "ave_i_frame_psnr_u": 43.928063, + "ave_i_frame_psnr_v": 43.847735, + "ave_i_frame_msssim_y": 0.984852, + "ave_i_frame_msssim_u": 0.987470, + "ave_i_frame_msssim_v": 0.987752, + "test_time": 71393.994396, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.042197, + "ave_all_frame_psnr": 40.206427, + "ave_all_frame_msssim": 0.985542, + "ave_all_frame_psnr_y": 38.979269, + "ave_all_frame_psnr_u": 43.928063, + "ave_all_frame_psnr_v": 43.847735, + "ave_all_frame_msssim_y": 0.984852, + "ave_all_frame_msssim_u": 0.987470, + "ave_all_frame_msssim_v": 0.987752, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.027312, + "ave_i_frame_psnr": 38.509062, + "ave_i_frame_msssim": 0.977546, + "ave_i_frame_psnr_y": 37.039713, + "ave_i_frame_psnr_u": 43.023460, + "ave_i_frame_psnr_v": 42.810760, + "ave_i_frame_msssim_y": 0.975361, + "ave_i_frame_msssim_u": 0.984080, + "ave_i_frame_msssim_v": 0.984122, + "test_time": 57123.978937, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.027312, + "ave_all_frame_psnr": 38.509062, + "ave_all_frame_msssim": 0.977546, + "ave_all_frame_psnr_y": 37.039713, + "ave_all_frame_psnr_u": 43.023460, + "ave_all_frame_psnr_v": 42.810760, + "ave_all_frame_msssim_y": 0.975361, + "ave_all_frame_msssim_u": 0.984080, + "ave_all_frame_msssim_v": 0.984122, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.018741, + "ave_i_frame_psnr": 37.026564, + "ave_i_frame_msssim": 0.967220, + "ave_i_frame_psnr_y": 35.413894, + "ave_i_frame_psnr_u": 42.079247, + "ave_i_frame_psnr_v": 41.649903, + "ave_i_frame_msssim_y": 0.963231, + "ave_i_frame_msssim_u": 0.979645, + "ave_i_frame_msssim_v": 0.978734, + "test_time": 44765.510062, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.018741, + "ave_all_frame_psnr": 37.026564, + "ave_all_frame_msssim": 0.967220, + "ave_all_frame_psnr_y": 35.413894, + "ave_all_frame_psnr_u": 42.079247, + "ave_all_frame_psnr_v": 41.649903, + "ave_all_frame_msssim_y": 0.963231, + "ave_all_frame_msssim_u": 0.979645, + "ave_all_frame_msssim_v": 0.978734, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012727, + "ave_i_frame_psnr": 35.598653, + "ave_i_frame_msssim": 0.953199, + "ave_i_frame_psnr_y": 33.811966, + "ave_i_frame_psnr_u": 41.083443, + "ave_i_frame_psnr_v": 40.833989, + "ave_i_frame_msssim_y": 0.946254, + "ave_i_frame_msssim_u": 0.974023, + "ave_i_frame_msssim_v": 0.974044, + "test_time": 34651.957324, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012727, + "ave_all_frame_psnr": 35.598653, + "ave_all_frame_msssim": 0.953199, + "ave_all_frame_psnr_y": 33.811966, + "ave_all_frame_psnr_u": 41.083443, + "ave_all_frame_psnr_v": 40.833989, + "ave_all_frame_msssim_y": 0.946254, + "ave_all_frame_msssim_u": 0.974023, + "ave_all_frame_msssim_v": 0.974044, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008527, + "ave_i_frame_psnr": 34.246894, + "ave_i_frame_msssim": 0.935358, + "ave_i_frame_psnr_y": 32.280195, + "ave_i_frame_psnr_u": 40.373974, + "ave_i_frame_psnr_v": 39.920007, + "ave_i_frame_msssim_y": 0.924398, + "ave_i_frame_msssim_u": 0.968873, + "ave_i_frame_msssim_v": 0.967605, + "test_time": 26674.103305, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008527, + "ave_all_frame_psnr": 34.246894, + "ave_all_frame_msssim": 0.935358, + "ave_all_frame_psnr_y": 32.280195, + "ave_all_frame_psnr_u": 40.373974, + "ave_all_frame_psnr_v": 39.920007, + "ave_all_frame_msssim_y": 0.924398, + "ave_all_frame_msssim_u": 0.968873, + "ave_all_frame_msssim_v": 0.967605, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005658, + "ave_i_frame_psnr": 32.956937, + "ave_i_frame_msssim": 0.913521, + "ave_i_frame_psnr_y": 30.809006, + "ave_i_frame_psnr_u": 39.653133, + "ave_i_frame_psnr_v": 39.148333, + "ave_i_frame_msssim_y": 0.897284, + "ave_i_frame_msssim_u": 0.963410, + "ave_i_frame_msssim_v": 0.961052, + "test_time": 19775.686455, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005658, + "ave_all_frame_psnr": 32.956937, + "ave_all_frame_msssim": 0.913521, + "ave_all_frame_psnr_y": 30.809006, + "ave_all_frame_psnr_u": 39.653133, + "ave_all_frame_psnr_v": 39.148333, + "ave_all_frame_msssim_y": 0.897284, + "ave_all_frame_msssim_u": 0.963410, + "ave_all_frame_msssim_v": 0.961052, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003674, + "ave_i_frame_psnr": 31.625546, + "ave_i_frame_msssim": 0.886877, + "ave_i_frame_psnr_y": 29.369083, + "ave_i_frame_psnr_u": 38.755818, + "ave_i_frame_psnr_v": 38.034051, + "ave_i_frame_msssim_y": 0.864829, + "ave_i_frame_msssim_u": 0.955193, + "ave_i_frame_msssim_v": 0.950848, + "test_time": 14311.310655, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003674, + "ave_all_frame_psnr": 31.625546, + "ave_all_frame_msssim": 0.886877, + "ave_all_frame_psnr_y": 29.369083, + "ave_all_frame_psnr_u": 38.755818, + "ave_all_frame_psnr_v": 38.034051, + "ave_all_frame_msssim_y": 0.864829, + "ave_all_frame_msssim_u": 0.955193, + "ave_all_frame_msssim_v": 0.950848, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002380, + "ave_i_frame_psnr": 30.359576, + "ave_i_frame_msssim": 0.857587, + "ave_i_frame_psnr_y": 28.012267, + "ave_i_frame_psnr_u": 37.826991, + "ave_i_frame_psnr_v": 36.976009, + "ave_i_frame_msssim_y": 0.829417, + "ave_i_frame_msssim_u": 0.945771, + "ave_i_frame_msssim_v": 0.938418, + "test_time": 8862.853216, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002380, + "ave_all_frame_psnr": 30.359576, + "ave_all_frame_msssim": 0.857587, + "ave_all_frame_psnr_y": 28.012267, + "ave_all_frame_psnr_u": 37.826991, + "ave_all_frame_psnr_v": 36.976009, + "ave_all_frame_msssim_y": 0.829417, + "ave_all_frame_msssim_u": 0.945771, + "ave_all_frame_msssim_v": 0.938418, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC19_1920x1080_30.yuv" + } + }, + "videoSRC20_1920x1080_25.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.039596, + "ave_i_frame_psnr": 46.499189, + "ave_i_frame_msssim": 0.997033, + "ave_i_frame_psnr_y": 45.961044, + "ave_i_frame_psnr_u": 47.623890, + "ave_i_frame_psnr_v": 48.603353, + "ave_i_frame_msssim_y": 0.996909, + "ave_i_frame_msssim_u": 0.997183, + "ave_i_frame_msssim_v": 0.997623, + "test_time": 34618.064792, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.039596, + "ave_all_frame_psnr": 46.499189, + "ave_all_frame_msssim": 0.997033, + "ave_all_frame_psnr_y": 45.961044, + "ave_all_frame_psnr_u": 47.623890, + "ave_all_frame_psnr_v": 48.603353, + "ave_all_frame_msssim_y": 0.996909, + "ave_all_frame_msssim_u": 0.997183, + "ave_all_frame_msssim_v": 0.997623, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.026926, + "ave_i_frame_psnr": 44.525572, + "ave_i_frame_msssim": 0.995137, + "ave_i_frame_psnr_y": 43.932700, + "ave_i_frame_psnr_u": 45.782135, + "ave_i_frame_psnr_v": 46.826238, + "ave_i_frame_msssim_y": 0.994856, + "ave_i_frame_msssim_u": 0.995601, + "ave_i_frame_msssim_v": 0.996360, + "test_time": 29478.314483, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.026926, + "ave_all_frame_psnr": 44.525572, + "ave_all_frame_msssim": 0.995137, + "ave_all_frame_psnr_y": 43.932700, + "ave_all_frame_psnr_u": 45.782135, + "ave_all_frame_psnr_v": 46.826238, + "ave_all_frame_msssim_y": 0.994856, + "ave_all_frame_msssim_u": 0.995601, + "ave_all_frame_msssim_v": 0.996360, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.018628, + "ave_i_frame_psnr": 42.613367, + "ave_i_frame_msssim": 0.992173, + "ave_i_frame_psnr_y": 41.933349, + "ave_i_frame_psnr_u": 44.179372, + "ave_i_frame_psnr_v": 45.127475, + "ave_i_frame_msssim_y": 0.991589, + "ave_i_frame_msssim_u": 0.993414, + "ave_i_frame_msssim_v": 0.994435, + "test_time": 25218.127123, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.018628, + "ave_all_frame_psnr": 42.613367, + "ave_all_frame_msssim": 0.992173, + "ave_all_frame_psnr_y": 41.933349, + "ave_all_frame_psnr_u": 44.179372, + "ave_all_frame_psnr_v": 45.127475, + "ave_all_frame_msssim_y": 0.991589, + "ave_all_frame_msssim_u": 0.993414, + "ave_all_frame_msssim_v": 0.994435, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013246, + "ave_i_frame_psnr": 40.773526, + "ave_i_frame_msssim": 0.987750, + "ave_i_frame_psnr_y": 39.953009, + "ave_i_frame_psnr_u": 42.799372, + "ave_i_frame_psnr_v": 43.670777, + "ave_i_frame_msssim_y": 0.986568, + "ave_i_frame_msssim_u": 0.990603, + "ave_i_frame_msssim_v": 0.991990, + "test_time": 21860.240581, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013246, + "ave_all_frame_psnr": 40.773526, + "ave_all_frame_msssim": 0.987750, + "ave_all_frame_psnr_y": 39.953009, + "ave_all_frame_psnr_u": 42.799372, + "ave_all_frame_psnr_v": 43.670777, + "ave_all_frame_msssim_y": 0.986568, + "ave_all_frame_msssim_u": 0.990603, + "ave_all_frame_msssim_v": 0.991990, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009746, + "ave_i_frame_psnr": 39.160773, + "ave_i_frame_msssim": 0.981920, + "ave_i_frame_psnr_y": 38.232043, + "ave_i_frame_psnr_u": 41.452901, + "ave_i_frame_psnr_v": 42.441025, + "ave_i_frame_msssim_y": 0.979939, + "ave_i_frame_msssim_u": 0.986858, + "ave_i_frame_msssim_v": 0.988868, + "test_time": 18655.092587, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009746, + "ave_all_frame_psnr": 39.160773, + "ave_all_frame_msssim": 0.981920, + "ave_all_frame_psnr_y": 38.232043, + "ave_all_frame_psnr_u": 41.452901, + "ave_all_frame_psnr_v": 42.441025, + "ave_all_frame_msssim_y": 0.979939, + "ave_all_frame_msssim_u": 0.986858, + "ave_all_frame_msssim_v": 0.988868, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007298, + "ave_i_frame_psnr": 37.631435, + "ave_i_frame_msssim": 0.974292, + "ave_i_frame_psnr_y": 36.568530, + "ave_i_frame_psnr_u": 40.348333, + "ave_i_frame_psnr_v": 41.291970, + "ave_i_frame_msssim_y": 0.970935, + "ave_i_frame_msssim_u": 0.983406, + "ave_i_frame_msssim_v": 0.985321, + "test_time": 16015.724488, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007298, + "ave_all_frame_psnr": 37.631435, + "ave_all_frame_msssim": 0.974292, + "ave_all_frame_psnr_y": 36.568530, + "ave_all_frame_psnr_u": 40.348333, + "ave_all_frame_psnr_v": 41.291970, + "ave_all_frame_msssim_y": 0.970935, + "ave_all_frame_msssim_u": 0.983406, + "ave_all_frame_msssim_v": 0.985321, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005432, + "ave_i_frame_psnr": 36.057010, + "ave_i_frame_msssim": 0.963627, + "ave_i_frame_psnr_y": 34.887707, + "ave_i_frame_psnr_u": 39.149181, + "ave_i_frame_psnr_v": 39.980655, + "ave_i_frame_msssim_y": 0.958480, + "ave_i_frame_msssim_u": 0.977948, + "ave_i_frame_msssim_v": 0.980187, + "test_time": 13485.105743, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005432, + "ave_all_frame_psnr": 36.057010, + "ave_all_frame_msssim": 0.963627, + "ave_all_frame_psnr_y": 34.887707, + "ave_all_frame_psnr_u": 39.149181, + "ave_all_frame_psnr_v": 39.980655, + "ave_all_frame_msssim_y": 0.958480, + "ave_all_frame_msssim_u": 0.977948, + "ave_all_frame_msssim_v": 0.980187, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004057, + "ave_i_frame_psnr": 34.487590, + "ave_i_frame_msssim": 0.949820, + "ave_i_frame_psnr_y": 33.188742, + "ave_i_frame_psnr_u": 37.903264, + "ave_i_frame_psnr_v": 38.865005, + "ave_i_frame_msssim_y": 0.941898, + "ave_i_frame_msssim_u": 0.972019, + "ave_i_frame_msssim_v": 0.975148, + "test_time": 11205.581405, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004057, + "ave_all_frame_psnr": 34.487590, + "ave_all_frame_msssim": 0.949820, + "ave_all_frame_psnr_y": 33.188742, + "ave_all_frame_psnr_u": 37.903264, + "ave_all_frame_psnr_v": 38.865005, + "ave_all_frame_msssim_y": 0.941898, + "ave_all_frame_msssim_u": 0.972019, + "ave_all_frame_msssim_v": 0.975148, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002936, + "ave_i_frame_psnr": 32.761938, + "ave_i_frame_msssim": 0.929914, + "ave_i_frame_psnr_y": 31.431952, + "ave_i_frame_psnr_u": 36.266882, + "ave_i_frame_psnr_v": 37.236910, + "ave_i_frame_msssim_y": 0.918952, + "ave_i_frame_msssim_u": 0.960471, + "ave_i_frame_msssim_v": 0.965129, + "test_time": 9076.932284, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002936, + "ave_all_frame_psnr": 32.761938, + "ave_all_frame_msssim": 0.929914, + "ave_all_frame_psnr_y": 31.431952, + "ave_all_frame_psnr_u": 36.266882, + "ave_all_frame_psnr_v": 37.236910, + "ave_all_frame_msssim_y": 0.918952, + "ave_all_frame_msssim_u": 0.960471, + "ave_all_frame_msssim_v": 0.965129, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 125, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002068, + "ave_i_frame_psnr": 31.057577, + "ave_i_frame_msssim": 0.904095, + "ave_i_frame_psnr_y": 29.727877, + "ave_i_frame_psnr_u": 34.602915, + "ave_i_frame_psnr_v": 35.490443, + "ave_i_frame_msssim_y": 0.889371, + "ave_i_frame_msssim_u": 0.944668, + "ave_i_frame_msssim_v": 0.951860, + "test_time": 6676.046819, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002068, + "ave_all_frame_psnr": 31.057577, + "ave_all_frame_msssim": 0.904095, + "ave_all_frame_psnr_y": 29.727877, + "ave_all_frame_psnr_u": 34.602915, + "ave_all_frame_psnr_v": 35.490443, + "ave_all_frame_msssim_y": 0.889371, + "ave_all_frame_msssim_u": 0.944668, + "ave_all_frame_msssim_v": 0.951860, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC20_1920x1080_25.yuv" + } + }, + "videoSRC21_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.044026, + "ave_i_frame_psnr": 47.690990, + "ave_i_frame_msssim": 0.995417, + "ave_i_frame_psnr_y": 46.956704, + "ave_i_frame_psnr_u": 50.059387, + "ave_i_frame_psnr_v": 49.728306, + "ave_i_frame_msssim_y": 0.994991, + "ave_i_frame_msssim_u": 0.996877, + "ave_i_frame_msssim_v": 0.996516, + "test_time": 55496.714324, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.044026, + "ave_all_frame_psnr": 47.690990, + "ave_all_frame_msssim": 0.995417, + "ave_all_frame_psnr_y": 46.956704, + "ave_all_frame_psnr_u": 50.059387, + "ave_all_frame_psnr_v": 49.728306, + "ave_all_frame_msssim_y": 0.994991, + "ave_all_frame_msssim_u": 0.996877, + "ave_all_frame_msssim_v": 0.996516, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.027833, + "ave_i_frame_psnr": 46.507786, + "ave_i_frame_msssim": 0.993819, + "ave_i_frame_psnr_y": 45.691935, + "ave_i_frame_psnr_u": 49.095287, + "ave_i_frame_psnr_v": 48.815393, + "ave_i_frame_msssim_y": 0.993152, + "ave_i_frame_msssim_u": 0.996028, + "ave_i_frame_msssim_v": 0.995613, + "test_time": 43066.859581, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.027833, + "ave_all_frame_psnr": 46.507786, + "ave_all_frame_msssim": 0.993819, + "ave_all_frame_psnr_y": 45.691935, + "ave_all_frame_psnr_u": 49.095287, + "ave_all_frame_psnr_v": 48.815393, + "ave_all_frame_msssim_y": 0.993152, + "ave_all_frame_msssim_u": 0.996028, + "ave_all_frame_msssim_v": 0.995613, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017572, + "ave_i_frame_psnr": 45.123795, + "ave_i_frame_msssim": 0.991288, + "ave_i_frame_psnr_y": 44.180134, + "ave_i_frame_psnr_u": 48.075036, + "ave_i_frame_psnr_v": 47.834519, + "ave_i_frame_msssim_y": 0.990145, + "ave_i_frame_msssim_u": 0.994976, + "ave_i_frame_msssim_v": 0.994460, + "test_time": 31364.252712, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017572, + "ave_all_frame_psnr": 45.123795, + "ave_all_frame_msssim": 0.991288, + "ave_all_frame_psnr_y": 44.180134, + "ave_all_frame_psnr_u": 48.075036, + "ave_all_frame_psnr_v": 47.834519, + "ave_all_frame_msssim_y": 0.990145, + "ave_all_frame_msssim_u": 0.994976, + "ave_all_frame_msssim_v": 0.994460, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011142, + "ave_i_frame_psnr": 43.665909, + "ave_i_frame_msssim": 0.987652, + "ave_i_frame_psnr_y": 42.507477, + "ave_i_frame_psnr_u": 47.252749, + "ave_i_frame_psnr_v": 47.029663, + "ave_i_frame_msssim_y": 0.985636, + "ave_i_frame_msssim_u": 0.993981, + "ave_i_frame_msssim_v": 0.993418, + "test_time": 22713.847243, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011142, + "ave_all_frame_psnr": 43.665909, + "ave_all_frame_msssim": 0.987652, + "ave_all_frame_psnr_y": 42.507477, + "ave_all_frame_psnr_u": 47.252749, + "ave_all_frame_psnr_v": 47.029663, + "ave_all_frame_msssim_y": 0.985636, + "ave_all_frame_msssim_u": 0.993981, + "ave_all_frame_msssim_v": 0.993418, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007632, + "ave_i_frame_psnr": 42.364587, + "ave_i_frame_msssim": 0.983559, + "ave_i_frame_psnr_y": 41.098138, + "ave_i_frame_psnr_u": 46.279310, + "ave_i_frame_psnr_v": 46.048561, + "ave_i_frame_msssim_y": 0.980663, + "ave_i_frame_msssim_u": 0.992579, + "ave_i_frame_msssim_v": 0.991920, + "test_time": 17007.956131, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007632, + "ave_all_frame_psnr": 42.364587, + "ave_all_frame_msssim": 0.983559, + "ave_all_frame_psnr_y": 41.098138, + "ave_all_frame_psnr_u": 46.279310, + "ave_all_frame_psnr_v": 46.048561, + "ave_all_frame_msssim_y": 0.980663, + "ave_all_frame_msssim_u": 0.992579, + "ave_all_frame_msssim_v": 0.991920, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005222, + "ave_i_frame_psnr": 41.105971, + "ave_i_frame_msssim": 0.978562, + "ave_i_frame_psnr_y": 39.653279, + "ave_i_frame_psnr_u": 45.500111, + "ave_i_frame_psnr_v": 45.427987, + "ave_i_frame_msssim_y": 0.974397, + "ave_i_frame_msssim_u": 0.991393, + "ave_i_frame_msssim_v": 0.990718, + "test_time": 12946.654217, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005222, + "ave_all_frame_psnr": 41.105971, + "ave_all_frame_msssim": 0.978562, + "ave_all_frame_psnr_y": 39.653279, + "ave_all_frame_psnr_u": 45.500111, + "ave_all_frame_psnr_v": 45.427987, + "ave_all_frame_msssim_y": 0.974397, + "ave_all_frame_msssim_u": 0.991393, + "ave_all_frame_msssim_v": 0.990718, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003545, + "ave_i_frame_psnr": 39.767547, + "ave_i_frame_msssim": 0.972347, + "ave_i_frame_psnr_y": 38.206668, + "ave_i_frame_psnr_u": 44.504494, + "ave_i_frame_psnr_v": 44.395875, + "ave_i_frame_msssim_y": 0.966787, + "ave_i_frame_msssim_u": 0.989420, + "ave_i_frame_msssim_v": 0.988634, + "test_time": 9512.615753, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003545, + "ave_all_frame_psnr": 39.767547, + "ave_all_frame_msssim": 0.972347, + "ave_all_frame_psnr_y": 38.206668, + "ave_all_frame_psnr_u": 44.504494, + "ave_all_frame_psnr_v": 44.395875, + "ave_all_frame_msssim_y": 0.966787, + "ave_all_frame_msssim_u": 0.989420, + "ave_all_frame_msssim_v": 0.988634, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002415, + "ave_i_frame_psnr": 38.415927, + "ave_i_frame_msssim": 0.964787, + "ave_i_frame_psnr_y": 36.719467, + "ave_i_frame_psnr_u": 43.520376, + "ave_i_frame_psnr_v": 43.490239, + "ave_i_frame_msssim_y": 0.957469, + "ave_i_frame_msssim_u": 0.987246, + "ave_i_frame_msssim_v": 0.986237, + "test_time": 7242.512917, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002415, + "ave_all_frame_psnr": 38.415927, + "ave_all_frame_msssim": 0.964787, + "ave_all_frame_psnr_y": 36.719467, + "ave_all_frame_psnr_u": 43.520376, + "ave_all_frame_psnr_v": 43.490239, + "ave_all_frame_msssim_y": 0.957469, + "ave_all_frame_msssim_u": 0.987246, + "ave_all_frame_msssim_v": 0.986237, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001643, + "ave_i_frame_psnr": 36.969227, + "ave_i_frame_msssim": 0.955793, + "ave_i_frame_psnr_y": 35.208538, + "ave_i_frame_psnr_u": 42.253171, + "ave_i_frame_psnr_v": 42.249422, + "ave_i_frame_msssim_y": 0.946558, + "ave_i_frame_msssim_u": 0.984110, + "ave_i_frame_msssim_v": 0.982886, + "test_time": 5530.971504, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001643, + "ave_all_frame_psnr": 36.969227, + "ave_all_frame_msssim": 0.955793, + "ave_all_frame_psnr_y": 35.208538, + "ave_all_frame_psnr_u": 42.253171, + "ave_all_frame_psnr_v": 42.249422, + "ave_all_frame_msssim_y": 0.946558, + "ave_all_frame_msssim_u": 0.984110, + "ave_all_frame_msssim_v": 0.982886, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001126, + "ave_i_frame_psnr": 35.429275, + "ave_i_frame_msssim": 0.944332, + "ave_i_frame_psnr_y": 33.638896, + "ave_i_frame_psnr_u": 40.747375, + "ave_i_frame_psnr_v": 40.853446, + "ave_i_frame_msssim_y": 0.932744, + "ave_i_frame_msssim_u": 0.980018, + "ave_i_frame_msssim_v": 0.978173, + "test_time": 4328.036729, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001126, + "ave_all_frame_psnr": 35.429275, + "ave_all_frame_msssim": 0.944332, + "ave_all_frame_psnr_y": 33.638896, + "ave_all_frame_psnr_u": 40.747375, + "ave_all_frame_psnr_v": 40.853446, + "ave_all_frame_msssim_y": 0.932744, + "ave_all_frame_msssim_u": 0.980018, + "ave_all_frame_msssim_v": 0.978173, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC21_1920x1080_24.yuv" + } + }, + "videoSRC22_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.181025, + "ave_i_frame_psnr": 44.409112, + "ave_i_frame_msssim": 0.994090, + "ave_i_frame_psnr_y": 43.203809, + "ave_i_frame_psnr_u": 47.542270, + "ave_i_frame_psnr_v": 48.507766, + "ave_i_frame_msssim_y": 0.994063, + "ave_i_frame_msssim_u": 0.993671, + "ave_i_frame_msssim_v": 0.994672, + "test_time": 126167.977566, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.181025, + "ave_all_frame_psnr": 44.409112, + "ave_all_frame_msssim": 0.994090, + "ave_all_frame_psnr_y": 43.203809, + "ave_all_frame_psnr_u": 47.542270, + "ave_all_frame_psnr_v": 48.507766, + "ave_all_frame_msssim_y": 0.994063, + "ave_all_frame_msssim_u": 0.993671, + "ave_all_frame_msssim_v": 0.994672, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.117144, + "ave_i_frame_psnr": 42.770513, + "ave_i_frame_msssim": 0.991009, + "ave_i_frame_psnr_y": 41.347554, + "ave_i_frame_psnr_u": 46.537829, + "ave_i_frame_psnr_v": 47.540949, + "ave_i_frame_msssim_y": 0.990558, + "ave_i_frame_msssim_u": 0.991552, + "ave_i_frame_msssim_v": 0.993171, + "test_time": 107322.983225, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.117144, + "ave_all_frame_psnr": 42.770513, + "ave_all_frame_msssim": 0.991009, + "ave_all_frame_psnr_y": 41.347554, + "ave_all_frame_psnr_u": 46.537829, + "ave_all_frame_psnr_v": 47.540949, + "ave_all_frame_msssim_y": 0.990558, + "ave_all_frame_msssim_u": 0.991552, + "ave_all_frame_msssim_v": 0.993171, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.076282, + "ave_i_frame_psnr": 41.038562, + "ave_i_frame_msssim": 0.985997, + "ave_i_frame_psnr_y": 39.340916, + "ave_i_frame_psnr_u": 45.602841, + "ave_i_frame_psnr_v": 46.660160, + "ave_i_frame_msssim_y": 0.984529, + "ave_i_frame_msssim_u": 0.989230, + "ave_i_frame_msssim_v": 0.991574, + "test_time": 87413.235557, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.076282, + "ave_all_frame_psnr": 41.038562, + "ave_all_frame_msssim": 0.985997, + "ave_all_frame_psnr_y": 39.340916, + "ave_all_frame_psnr_u": 45.602841, + "ave_all_frame_psnr_v": 46.660160, + "ave_all_frame_msssim_y": 0.984529, + "ave_all_frame_msssim_u": 0.989230, + "ave_all_frame_msssim_v": 0.991574, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.048954, + "ave_i_frame_psnr": 39.278075, + "ave_i_frame_msssim": 0.977875, + "ave_i_frame_psnr_y": 37.191655, + "ave_i_frame_psnr_u": 44.975015, + "ave_i_frame_psnr_v": 46.099659, + "ave_i_frame_msssim_y": 0.974184, + "ave_i_frame_msssim_u": 0.987495, + "ave_i_frame_msssim_v": 0.990399, + "test_time": 67863.388968, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.048954, + "ave_all_frame_psnr": 39.278075, + "ave_all_frame_msssim": 0.977875, + "ave_all_frame_psnr_y": 37.191655, + "ave_all_frame_psnr_u": 44.975015, + "ave_all_frame_psnr_v": 46.099659, + "ave_all_frame_msssim_y": 0.974184, + "ave_all_frame_msssim_u": 0.987495, + "ave_all_frame_msssim_v": 0.990399, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.033630, + "ave_i_frame_psnr": 37.811653, + "ave_i_frame_msssim": 0.968121, + "ave_i_frame_psnr_y": 35.462531, + "ave_i_frame_psnr_u": 44.279989, + "ave_i_frame_psnr_v": 45.438046, + "ave_i_frame_msssim_y": 0.961726, + "ave_i_frame_msssim_u": 0.985532, + "ave_i_frame_msssim_v": 0.989082, + "test_time": 51344.696219, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.033630, + "ave_all_frame_psnr": 37.811653, + "ave_all_frame_msssim": 0.968121, + "ave_all_frame_psnr_y": 35.462531, + "ave_all_frame_psnr_u": 44.279989, + "ave_all_frame_psnr_v": 45.438046, + "ave_all_frame_msssim_y": 0.961726, + "ave_all_frame_msssim_u": 0.985532, + "ave_all_frame_msssim_v": 0.989082, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022490, + "ave_i_frame_psnr": 36.389269, + "ave_i_frame_msssim": 0.954313, + "ave_i_frame_psnr_y": 33.717212, + "ave_i_frame_psnr_u": 43.812595, + "ave_i_frame_psnr_v": 44.998285, + "ave_i_frame_msssim_y": 0.943685, + "ave_i_frame_msssim_u": 0.984167, + "ave_i_frame_msssim_v": 0.988222, + "test_time": 40784.238423, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022490, + "ave_all_frame_psnr": 36.389269, + "ave_all_frame_msssim": 0.954313, + "ave_all_frame_psnr_y": 33.717212, + "ave_all_frame_psnr_u": 43.812595, + "ave_all_frame_psnr_v": 44.998285, + "ave_all_frame_msssim_y": 0.943685, + "ave_all_frame_msssim_u": 0.984167, + "ave_all_frame_msssim_v": 0.988222, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014656, + "ave_i_frame_psnr": 34.921407, + "ave_i_frame_msssim": 0.935257, + "ave_i_frame_psnr_y": 32.014810, + "ave_i_frame_psnr_u": 42.999406, + "ave_i_frame_psnr_v": 44.282988, + "ave_i_frame_msssim_y": 0.918905, + "ave_i_frame_msssim_u": 0.981992, + "ave_i_frame_msssim_v": 0.986640, + "test_time": 30351.907440, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014656, + "ave_all_frame_psnr": 34.921407, + "ave_all_frame_msssim": 0.935257, + "ave_all_frame_psnr_y": 32.014810, + "ave_all_frame_psnr_u": 42.999406, + "ave_all_frame_psnr_v": 44.282988, + "ave_all_frame_msssim_y": 0.918905, + "ave_all_frame_msssim_u": 0.981992, + "ave_all_frame_msssim_v": 0.986640, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009265, + "ave_i_frame_psnr": 33.497726, + "ave_i_frame_msssim": 0.910534, + "ave_i_frame_psnr_y": 30.376291, + "ave_i_frame_psnr_u": 42.272200, + "ave_i_frame_psnr_v": 43.451861, + "ave_i_frame_msssim_y": 0.886501, + "ave_i_frame_msssim_u": 0.979962, + "ave_i_frame_msssim_v": 0.985303, + "test_time": 21330.902320, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009265, + "ave_all_frame_psnr": 33.497726, + "ave_all_frame_msssim": 0.910534, + "ave_all_frame_psnr_y": 30.376291, + "ave_all_frame_psnr_u": 42.272200, + "ave_all_frame_psnr_v": 43.451861, + "ave_all_frame_msssim_y": 0.886501, + "ave_all_frame_msssim_u": 0.979962, + "ave_all_frame_msssim_v": 0.985303, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005738, + "ave_i_frame_psnr": 32.096496, + "ave_i_frame_msssim": 0.880576, + "ave_i_frame_psnr_y": 28.841012, + "ave_i_frame_psnr_u": 41.190727, + "ave_i_frame_psnr_v": 42.535168, + "ave_i_frame_msssim_y": 0.847316, + "ave_i_frame_msssim_u": 0.977346, + "ave_i_frame_msssim_v": 0.983367, + "test_time": 14883.887471, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005738, + "ave_all_frame_psnr": 32.096496, + "ave_all_frame_msssim": 0.880576, + "ave_all_frame_psnr_y": 28.841012, + "ave_all_frame_psnr_u": 41.190727, + "ave_all_frame_psnr_v": 42.535168, + "ave_all_frame_msssim_y": 0.847316, + "ave_all_frame_msssim_u": 0.977346, + "ave_all_frame_msssim_v": 0.983367, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003514, + "ave_i_frame_psnr": 30.912001, + "ave_i_frame_msssim": 0.846836, + "ave_i_frame_psnr_y": 27.425638, + "ave_i_frame_psnr_u": 40.482588, + "ave_i_frame_psnr_v": 42.259596, + "ave_i_frame_msssim_y": 0.802868, + "ave_i_frame_msssim_u": 0.975487, + "ave_i_frame_msssim_v": 0.981991, + "test_time": 8583.650316, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003514, + "ave_all_frame_psnr": 30.912001, + "ave_all_frame_msssim": 0.846836, + "ave_all_frame_psnr_y": 27.425638, + "ave_all_frame_psnr_u": 40.482588, + "ave_all_frame_psnr_v": 42.259596, + "ave_all_frame_msssim_y": 0.802868, + "ave_all_frame_msssim_u": 0.975487, + "ave_all_frame_msssim_v": 0.981991, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC22_1920x1080_24.yuv" + } + }, + "videoSRC23_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.059965, + "ave_i_frame_psnr": 44.961432, + "ave_i_frame_msssim": 0.995644, + "ave_i_frame_psnr_y": 43.987339, + "ave_i_frame_psnr_u": 48.485222, + "ave_i_frame_psnr_v": 47.282197, + "ave_i_frame_msssim_y": 0.995814, + "ave_i_frame_msssim_u": 0.995428, + "ave_i_frame_msssim_v": 0.994844, + "test_time": 54643.919242, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.059965, + "ave_all_frame_psnr": 44.961432, + "ave_all_frame_msssim": 0.995644, + "ave_all_frame_psnr_y": 43.987339, + "ave_all_frame_psnr_u": 48.485222, + "ave_all_frame_psnr_v": 47.282197, + "ave_all_frame_msssim_y": 0.995814, + "ave_all_frame_msssim_u": 0.995428, + "ave_all_frame_msssim_v": 0.994844, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.036896, + "ave_i_frame_psnr": 43.438495, + "ave_i_frame_msssim": 0.993814, + "ave_i_frame_psnr_y": 42.309712, + "ave_i_frame_psnr_u": 47.538046, + "ave_i_frame_psnr_v": 46.111644, + "ave_i_frame_msssim_y": 0.993915, + "ave_i_frame_msssim_u": 0.994159, + "ave_i_frame_msssim_v": 0.992862, + "test_time": 44344.652956, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.036896, + "ave_all_frame_psnr": 43.438495, + "ave_all_frame_msssim": 0.993814, + "ave_all_frame_psnr_y": 42.309712, + "ave_all_frame_psnr_u": 47.538046, + "ave_all_frame_psnr_v": 46.111644, + "ave_all_frame_msssim_y": 0.993915, + "ave_all_frame_msssim_u": 0.994159, + "ave_all_frame_msssim_v": 0.992862, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.023153, + "ave_i_frame_psnr": 41.826084, + "ave_i_frame_msssim": 0.990992, + "ave_i_frame_psnr_y": 40.527839, + "ave_i_frame_psnr_u": 46.527783, + "ave_i_frame_psnr_v": 44.913855, + "ave_i_frame_msssim_y": 0.990883, + "ave_i_frame_msssim_u": 0.992497, + "ave_i_frame_msssim_v": 0.990143, + "test_time": 35345.446220, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.023153, + "ave_all_frame_psnr": 41.826084, + "ave_all_frame_msssim": 0.990992, + "ave_all_frame_psnr_y": 40.527839, + "ave_all_frame_psnr_u": 46.527783, + "ave_all_frame_psnr_v": 44.913855, + "ave_all_frame_msssim_y": 0.990883, + "ave_all_frame_msssim_u": 0.992497, + "ave_all_frame_msssim_v": 0.990143, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014685, + "ave_i_frame_psnr": 40.180344, + "ave_i_frame_msssim": 0.986761, + "ave_i_frame_psnr_y": 38.675143, + "ave_i_frame_psnr_u": 45.538786, + "ave_i_frame_psnr_v": 43.853106, + "ave_i_frame_msssim_y": 0.986083, + "ave_i_frame_msssim_u": 0.990575, + "ave_i_frame_msssim_v": 0.987015, + "test_time": 27312.679588, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014685, + "ave_all_frame_psnr": 40.180344, + "ave_all_frame_msssim": 0.986761, + "ave_all_frame_psnr_y": 38.675143, + "ave_all_frame_psnr_u": 45.538786, + "ave_all_frame_psnr_v": 43.853106, + "ave_all_frame_msssim_y": 0.986083, + "ave_all_frame_msssim_u": 0.990575, + "ave_all_frame_msssim_v": 0.987015, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009914, + "ave_i_frame_psnr": 38.672539, + "ave_i_frame_msssim": 0.981062, + "ave_i_frame_psnr_y": 37.044638, + "ave_i_frame_psnr_u": 44.402787, + "ave_i_frame_psnr_v": 42.709694, + "ave_i_frame_msssim_y": 0.979635, + "ave_i_frame_msssim_u": 0.987978, + "ave_i_frame_msssim_v": 0.982708, + "test_time": 20901.305797, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009914, + "ave_all_frame_psnr": 38.672539, + "ave_all_frame_msssim": 0.981062, + "ave_all_frame_psnr_y": 37.044638, + "ave_all_frame_psnr_u": 44.402787, + "ave_all_frame_psnr_v": 42.709694, + "ave_all_frame_msssim_y": 0.979635, + "ave_all_frame_msssim_u": 0.987978, + "ave_all_frame_msssim_v": 0.982708, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006664, + "ave_i_frame_psnr": 37.258601, + "ave_i_frame_msssim": 0.973195, + "ave_i_frame_psnr_y": 35.404096, + "ave_i_frame_psnr_u": 43.609693, + "ave_i_frame_psnr_v": 42.034539, + "ave_i_frame_msssim_y": 0.970099, + "ave_i_frame_msssim_u": 0.985667, + "ave_i_frame_msssim_v": 0.979300, + "test_time": 16255.755041, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006664, + "ave_all_frame_psnr": 37.258601, + "ave_all_frame_msssim": 0.973195, + "ave_all_frame_psnr_y": 35.404096, + "ave_all_frame_psnr_u": 43.609693, + "ave_all_frame_psnr_v": 42.034539, + "ave_all_frame_msssim_y": 0.970099, + "ave_all_frame_msssim_u": 0.985667, + "ave_all_frame_msssim_v": 0.979300, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004427, + "ave_i_frame_psnr": 35.799883, + "ave_i_frame_msssim": 0.961666, + "ave_i_frame_psnr_y": 33.752710, + "ave_i_frame_psnr_u": 42.688220, + "ave_i_frame_psnr_v": 41.194585, + "ave_i_frame_msssim_y": 0.956050, + "ave_i_frame_msssim_u": 0.982539, + "ave_i_frame_msssim_v": 0.974491, + "test_time": 12364.405516, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004427, + "ave_all_frame_psnr": 35.799883, + "ave_all_frame_msssim": 0.961666, + "ave_all_frame_psnr_y": 33.752710, + "ave_all_frame_psnr_u": 42.688220, + "ave_all_frame_psnr_v": 41.194585, + "ave_all_frame_msssim_y": 0.956050, + "ave_all_frame_msssim_u": 0.982539, + "ave_all_frame_msssim_v": 0.974491, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002921, + "ave_i_frame_psnr": 34.403165, + "ave_i_frame_msssim": 0.946348, + "ave_i_frame_psnr_y": 32.131217, + "ave_i_frame_psnr_u": 41.905862, + "ave_i_frame_psnr_v": 40.532159, + "ave_i_frame_msssim_y": 0.936854, + "ave_i_frame_msssim_u": 0.979551, + "ave_i_frame_msssim_v": 0.970112, + "test_time": 9576.741942, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002921, + "ave_all_frame_psnr": 34.403165, + "ave_all_frame_msssim": 0.946348, + "ave_all_frame_psnr_y": 32.131217, + "ave_all_frame_psnr_u": 41.905862, + "ave_all_frame_psnr_v": 40.532159, + "ave_all_frame_msssim_y": 0.936854, + "ave_all_frame_msssim_u": 0.979551, + "ave_all_frame_msssim_v": 0.970112, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001895, + "ave_i_frame_psnr": 32.916424, + "ave_i_frame_msssim": 0.925430, + "ave_i_frame_psnr_y": 30.553281, + "ave_i_frame_psnr_u": 40.589854, + "ave_i_frame_psnr_v": 39.421853, + "ave_i_frame_msssim_y": 0.911418, + "ave_i_frame_msssim_u": 0.972811, + "ave_i_frame_msssim_v": 0.962121, + "test_time": 7213.514639, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001895, + "ave_all_frame_psnr": 32.916424, + "ave_all_frame_msssim": 0.925430, + "ave_all_frame_psnr_y": 30.553281, + "ave_all_frame_psnr_u": 40.589854, + "ave_all_frame_psnr_v": 39.421853, + "ave_all_frame_msssim_y": 0.911418, + "ave_all_frame_msssim_u": 0.972811, + "ave_all_frame_msssim_v": 0.962121, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001212, + "ave_i_frame_psnr": 31.445607, + "ave_i_frame_msssim": 0.897671, + "ave_i_frame_psnr_y": 29.038083, + "ave_i_frame_psnr_u": 39.052060, + "ave_i_frame_psnr_v": 38.284298, + "ave_i_frame_msssim_y": 0.877779, + "ave_i_frame_msssim_u": 0.962700, + "ave_i_frame_msssim_v": 0.951992, + "test_time": 5079.050457, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001212, + "ave_all_frame_psnr": 31.445607, + "ave_all_frame_msssim": 0.897671, + "ave_all_frame_psnr_y": 29.038083, + "ave_all_frame_psnr_u": 39.052060, + "ave_all_frame_psnr_v": 38.284298, + "ave_all_frame_msssim_y": 0.877779, + "ave_all_frame_msssim_u": 0.962700, + "ave_all_frame_msssim_v": 0.951992, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC23_1920x1080_24.yuv" + } + }, + "videoSRC24_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.054688, + "ave_i_frame_psnr": 45.954511, + "ave_i_frame_msssim": 0.996975, + "ave_i_frame_psnr_y": 45.644609, + "ave_i_frame_psnr_u": 47.008904, + "ave_i_frame_psnr_v": 46.759523, + "ave_i_frame_msssim_y": 0.996960, + "ave_i_frame_msssim_u": 0.996894, + "ave_i_frame_msssim_v": 0.997148, + "test_time": 59074.548592, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.054688, + "ave_all_frame_psnr": 45.954511, + "ave_all_frame_msssim": 0.996975, + "ave_all_frame_psnr_y": 45.644609, + "ave_all_frame_psnr_u": 47.008904, + "ave_all_frame_psnr_v": 46.759523, + "ave_all_frame_msssim_y": 0.996960, + "ave_all_frame_msssim_u": 0.996894, + "ave_all_frame_msssim_v": 0.997148, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.033296, + "ave_i_frame_psnr": 44.422208, + "ave_i_frame_msssim": 0.995867, + "ave_i_frame_psnr_y": 44.174901, + "ave_i_frame_psnr_u": 45.328564, + "ave_i_frame_psnr_v": 44.999696, + "ave_i_frame_msssim_y": 0.995939, + "ave_i_frame_msssim_u": 0.995441, + "ave_i_frame_msssim_v": 0.995858, + "test_time": 46409.834249, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.033296, + "ave_all_frame_psnr": 44.422208, + "ave_all_frame_msssim": 0.995867, + "ave_all_frame_psnr_y": 44.174901, + "ave_all_frame_psnr_u": 45.328564, + "ave_all_frame_psnr_v": 44.999696, + "ave_all_frame_msssim_y": 0.995939, + "ave_all_frame_msssim_u": 0.995441, + "ave_all_frame_msssim_v": 0.995858, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.020771, + "ave_i_frame_psnr": 42.782946, + "ave_i_frame_msssim": 0.994133, + "ave_i_frame_psnr_y": 42.540215, + "ave_i_frame_psnr_u": 43.729929, + "ave_i_frame_psnr_v": 43.292353, + "ave_i_frame_msssim_y": 0.994311, + "ave_i_frame_msssim_u": 0.993359, + "ave_i_frame_msssim_v": 0.993838, + "test_time": 36945.832681, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.020771, + "ave_all_frame_psnr": 42.782946, + "ave_all_frame_msssim": 0.994133, + "ave_all_frame_psnr_y": 42.540215, + "ave_all_frame_psnr_u": 43.729929, + "ave_all_frame_psnr_v": 43.292353, + "ave_all_frame_msssim_y": 0.994311, + "ave_all_frame_msssim_u": 0.993359, + "ave_all_frame_msssim_v": 0.993838, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013387, + "ave_i_frame_psnr": 41.139334, + "ave_i_frame_msssim": 0.991611, + "ave_i_frame_psnr_y": 40.790954, + "ave_i_frame_psnr_u": 42.425757, + "ave_i_frame_psnr_v": 41.943188, + "ave_i_frame_msssim_y": 0.991755, + "ave_i_frame_msssim_u": 0.990784, + "ave_i_frame_msssim_v": 0.991575, + "test_time": 27654.835405, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013387, + "ave_all_frame_psnr": 41.139334, + "ave_all_frame_msssim": 0.991611, + "ave_all_frame_psnr_y": 40.790954, + "ave_all_frame_psnr_u": 42.425757, + "ave_all_frame_psnr_v": 41.943188, + "ave_all_frame_msssim_y": 0.991755, + "ave_all_frame_msssim_u": 0.990784, + "ave_all_frame_msssim_v": 0.991575, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009201, + "ave_i_frame_psnr": 39.661999, + "ave_i_frame_msssim": 0.988372, + "ave_i_frame_psnr_y": 39.277770, + "ave_i_frame_psnr_u": 41.095616, + "ave_i_frame_psnr_v": 40.533756, + "ave_i_frame_msssim_y": 0.988598, + "ave_i_frame_msssim_u": 0.987278, + "ave_i_frame_msssim_v": 0.988106, + "test_time": 20879.508987, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009201, + "ave_all_frame_psnr": 39.661999, + "ave_all_frame_msssim": 0.988372, + "ave_all_frame_psnr_y": 39.277770, + "ave_all_frame_psnr_u": 41.095616, + "ave_all_frame_psnr_v": 40.533756, + "ave_all_frame_msssim_y": 0.988598, + "ave_all_frame_msssim_u": 0.987278, + "ave_all_frame_msssim_v": 0.988106, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006488, + "ave_i_frame_psnr": 38.243631, + "ave_i_frame_msssim": 0.984187, + "ave_i_frame_psnr_y": 37.714760, + "ave_i_frame_psnr_u": 40.113317, + "ave_i_frame_psnr_v": 39.547174, + "ave_i_frame_msssim_y": 0.984055, + "ave_i_frame_msssim_u": 0.983961, + "ave_i_frame_msssim_v": 0.985208, + "test_time": 16467.988740, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006488, + "ave_all_frame_psnr": 38.243631, + "ave_all_frame_msssim": 0.984187, + "ave_all_frame_psnr_y": 37.714760, + "ave_all_frame_psnr_u": 40.113317, + "ave_all_frame_psnr_v": 39.547174, + "ave_all_frame_msssim_y": 0.984055, + "ave_all_frame_msssim_u": 0.983961, + "ave_all_frame_msssim_v": 0.985208, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004487, + "ave_i_frame_psnr": 36.710371, + "ave_i_frame_msssim": 0.977925, + "ave_i_frame_psnr_y": 36.088283, + "ave_i_frame_psnr_u": 38.912908, + "ave_i_frame_psnr_v": 38.240365, + "ave_i_frame_msssim_y": 0.977564, + "ave_i_frame_msssim_u": 0.978438, + "ave_i_frame_msssim_v": 0.979583, + "test_time": 12659.748704, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004487, + "ave_all_frame_psnr": 36.710371, + "ave_all_frame_msssim": 0.977925, + "ave_all_frame_psnr_y": 36.088283, + "ave_all_frame_psnr_u": 38.912908, + "ave_all_frame_psnr_v": 38.240365, + "ave_all_frame_msssim_y": 0.977564, + "ave_all_frame_msssim_u": 0.978438, + "ave_all_frame_msssim_v": 0.979583, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003131, + "ave_i_frame_psnr": 35.190407, + "ave_i_frame_msssim": 0.969428, + "ave_i_frame_psnr_y": 34.442148, + "ave_i_frame_psnr_u": 37.811924, + "ave_i_frame_psnr_v": 37.058445, + "ave_i_frame_msssim_y": 0.968451, + "ave_i_frame_msssim_u": 0.971686, + "ave_i_frame_msssim_v": 0.973029, + "test_time": 9845.475751, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003131, + "ave_all_frame_psnr": 35.190407, + "ave_all_frame_msssim": 0.969428, + "ave_all_frame_psnr_y": 34.442148, + "ave_all_frame_psnr_u": 37.811924, + "ave_all_frame_psnr_v": 37.058445, + "ave_all_frame_msssim_y": 0.968451, + "ave_all_frame_msssim_u": 0.971686, + "ave_all_frame_msssim_v": 0.973029, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002113, + "ave_i_frame_psnr": 33.540373, + "ave_i_frame_msssim": 0.956724, + "ave_i_frame_psnr_y": 32.748244, + "ave_i_frame_psnr_u": 36.288763, + "ave_i_frame_psnr_v": 35.544756, + "ave_i_frame_msssim_y": 0.955446, + "ave_i_frame_msssim_u": 0.959576, + "ave_i_frame_msssim_v": 0.961542, + "test_time": 7593.826220, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002113, + "ave_all_frame_psnr": 33.540373, + "ave_all_frame_msssim": 0.956724, + "ave_all_frame_psnr_y": 32.748244, + "ave_all_frame_psnr_u": 36.288763, + "ave_all_frame_psnr_v": 35.544756, + "ave_all_frame_msssim_y": 0.955446, + "ave_all_frame_msssim_u": 0.959576, + "ave_all_frame_msssim_v": 0.961542, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001415, + "ave_i_frame_psnr": 31.886805, + "ave_i_frame_msssim": 0.938785, + "ave_i_frame_psnr_y": 31.059044, + "ave_i_frame_psnr_u": 34.729572, + "ave_i_frame_psnr_v": 34.010605, + "ave_i_frame_msssim_y": 0.937254, + "ave_i_frame_msssim_u": 0.942338, + "ave_i_frame_msssim_v": 0.944419, + "test_time": 5238.315655, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001415, + "ave_all_frame_psnr": 31.886805, + "ave_all_frame_msssim": 0.938785, + "ave_all_frame_psnr_y": 31.059044, + "ave_all_frame_psnr_u": 34.729572, + "ave_all_frame_psnr_v": 34.010605, + "ave_all_frame_msssim_y": 0.937254, + "ave_all_frame_msssim_u": 0.942338, + "ave_all_frame_msssim_v": 0.944419, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC24_1920x1080_24.yuv" + } + }, + "videoSRC25_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.389474, + "ave_i_frame_psnr": 41.419847, + "ave_i_frame_msssim": 0.996066, + "ave_i_frame_psnr_y": 41.129092, + "ave_i_frame_psnr_u": 41.714177, + "ave_i_frame_psnr_v": 42.870046, + "ave_i_frame_msssim_y": 0.997044, + "ave_i_frame_msssim_u": 0.993661, + "ave_i_frame_msssim_v": 0.992608, + "test_time": 114890.348583, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.389474, + "ave_all_frame_psnr": 41.419847, + "ave_all_frame_msssim": 0.996066, + "ave_all_frame_psnr_y": 41.129092, + "ave_all_frame_psnr_u": 41.714177, + "ave_all_frame_psnr_v": 42.870046, + "ave_all_frame_msssim_y": 0.997044, + "ave_all_frame_msssim_u": 0.993661, + "ave_all_frame_msssim_v": 0.992608, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.228553, + "ave_i_frame_psnr": 38.933180, + "ave_i_frame_msssim": 0.992914, + "ave_i_frame_psnr_y": 38.505887, + "ave_i_frame_psnr_u": 39.467697, + "ave_i_frame_psnr_v": 40.962419, + "ave_i_frame_msssim_y": 0.994434, + "ave_i_frame_msssim_u": 0.988942, + "ave_i_frame_msssim_v": 0.987765, + "test_time": 102614.134319, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.228553, + "ave_all_frame_psnr": 38.933180, + "ave_all_frame_msssim": 0.992914, + "ave_all_frame_psnr_y": 38.505887, + "ave_all_frame_psnr_u": 39.467697, + "ave_all_frame_psnr_v": 40.962419, + "ave_all_frame_msssim_y": 0.994434, + "ave_all_frame_msssim_u": 0.988942, + "ave_all_frame_msssim_v": 0.987765, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.136206, + "ave_i_frame_psnr": 36.722760, + "ave_i_frame_msssim": 0.987682, + "ave_i_frame_psnr_y": 36.147596, + "ave_i_frame_psnr_u": 37.572384, + "ave_i_frame_psnr_v": 39.324115, + "ave_i_frame_msssim_y": 0.989693, + "ave_i_frame_msssim_u": 0.982031, + "ave_i_frame_msssim_v": 0.981270, + "test_time": 85971.957114, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.136206, + "ave_all_frame_psnr": 36.722760, + "ave_all_frame_msssim": 0.987682, + "ave_all_frame_psnr_y": 36.147596, + "ave_all_frame_psnr_u": 37.572384, + "ave_all_frame_psnr_v": 39.324115, + "ave_all_frame_msssim_y": 0.989693, + "ave_all_frame_msssim_u": 0.982031, + "ave_all_frame_msssim_v": 0.981270, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.082414, + "ave_i_frame_psnr": 34.725661, + "ave_i_frame_msssim": 0.979623, + "ave_i_frame_psnr_y": 33.892495, + "ave_i_frame_psnr_u": 36.294610, + "ave_i_frame_psnr_v": 38.155705, + "ave_i_frame_msssim_y": 0.981170, + "ave_i_frame_msssim_u": 0.975019, + "ave_i_frame_msssim_v": 0.974945, + "test_time": 76613.444876, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.082414, + "ave_all_frame_psnr": 34.725661, + "ave_all_frame_msssim": 0.979623, + "ave_all_frame_psnr_y": 33.892495, + "ave_all_frame_psnr_u": 36.294610, + "ave_all_frame_psnr_v": 38.155705, + "ave_all_frame_msssim_y": 0.981170, + "ave_all_frame_msssim_u": 0.975019, + "ave_all_frame_msssim_v": 0.974945, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.053067, + "ave_i_frame_psnr": 33.098185, + "ave_i_frame_msssim": 0.969154, + "ave_i_frame_psnr_y": 32.142333, + "ave_i_frame_psnr_u": 35.011924, + "ave_i_frame_psnr_v": 36.919559, + "ave_i_frame_msssim_y": 0.970379, + "ave_i_frame_msssim_u": 0.965252, + "ave_i_frame_msssim_v": 0.965707, + "test_time": 60311.704316, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.053067, + "ave_all_frame_psnr": 33.098185, + "ave_all_frame_msssim": 0.969154, + "ave_all_frame_psnr_y": 32.142333, + "ave_all_frame_psnr_u": 35.011924, + "ave_all_frame_psnr_v": 36.919559, + "ave_all_frame_msssim_y": 0.970379, + "ave_all_frame_msssim_u": 0.965252, + "ave_all_frame_msssim_v": 0.965707, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.033483, + "ave_i_frame_psnr": 31.567305, + "ave_i_frame_msssim": 0.954686, + "ave_i_frame_psnr_y": 30.453829, + "ave_i_frame_psnr_u": 33.840864, + "ave_i_frame_psnr_v": 35.974606, + "ave_i_frame_msssim_y": 0.954558, + "ave_i_frame_msssim_u": 0.953400, + "ave_i_frame_msssim_v": 0.956746, + "test_time": 46952.129086, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.033483, + "ave_all_frame_psnr": 31.567305, + "ave_all_frame_msssim": 0.954686, + "ave_all_frame_psnr_y": 30.453829, + "ave_all_frame_psnr_u": 33.840864, + "ave_all_frame_psnr_v": 35.974606, + "ave_all_frame_msssim_y": 0.954558, + "ave_all_frame_msssim_u": 0.953400, + "ave_all_frame_msssim_v": 0.956746, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.020107, + "ave_i_frame_psnr": 30.036986, + "ave_i_frame_msssim": 0.933600, + "ave_i_frame_psnr_y": 28.841016, + "ave_i_frame_psnr_u": 32.476230, + "ave_i_frame_psnr_v": 34.773559, + "ave_i_frame_msssim_y": 0.932145, + "ave_i_frame_msssim_u": 0.933978, + "ave_i_frame_msssim_v": 0.941957, + "test_time": 37311.516871, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.020107, + "ave_all_frame_psnr": 30.036986, + "ave_all_frame_msssim": 0.933600, + "ave_all_frame_psnr_y": 28.841016, + "ave_all_frame_psnr_u": 32.476230, + "ave_all_frame_psnr_v": 34.773559, + "ave_all_frame_msssim_y": 0.932145, + "ave_all_frame_msssim_u": 0.933978, + "ave_all_frame_msssim_v": 0.941957, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011753, + "ave_i_frame_psnr": 28.615115, + "ave_i_frame_msssim": 0.905970, + "ave_i_frame_psnr_y": 27.318754, + "ave_i_frame_psnr_u": 31.264240, + "ave_i_frame_psnr_v": 33.744156, + "ave_i_frame_msssim_y": 0.901836, + "ave_i_frame_msssim_u": 0.911017, + "ave_i_frame_msssim_v": 0.925724, + "test_time": 26864.577124, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011753, + "ave_all_frame_psnr": 28.615115, + "ave_all_frame_msssim": 0.905970, + "ave_all_frame_psnr_y": 27.318754, + "ave_all_frame_psnr_u": 31.264240, + "ave_all_frame_psnr_v": 33.744156, + "ave_all_frame_msssim_y": 0.901836, + "ave_all_frame_msssim_u": 0.911017, + "ave_all_frame_msssim_v": 0.925724, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006510, + "ave_i_frame_psnr": 27.258371, + "ave_i_frame_msssim": 0.870388, + "ave_i_frame_psnr_y": 25.899861, + "ave_i_frame_psnr_u": 30.109653, + "ave_i_frame_psnr_v": 32.558147, + "ave_i_frame_msssim_y": 0.863192, + "ave_i_frame_msssim_u": 0.881602, + "ave_i_frame_msssim_v": 0.902348, + "test_time": 17215.099505, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006510, + "ave_all_frame_psnr": 27.258371, + "ave_all_frame_msssim": 0.870388, + "ave_all_frame_psnr_y": 25.899861, + "ave_all_frame_psnr_u": 30.109653, + "ave_all_frame_psnr_v": 32.558147, + "ave_all_frame_msssim_y": 0.863192, + "ave_all_frame_msssim_u": 0.881602, + "ave_all_frame_msssim_v": 0.902348, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003576, + "ave_i_frame_psnr": 26.053273, + "ave_i_frame_msssim": 0.829714, + "ave_i_frame_psnr_y": 24.655252, + "ave_i_frame_psnr_u": 29.054625, + "ave_i_frame_psnr_v": 31.440045, + "ave_i_frame_msssim_y": 0.819058, + "ave_i_frame_msssim_u": 0.847864, + "ave_i_frame_msssim_v": 0.875499, + "test_time": 9565.973822, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003576, + "ave_all_frame_psnr": 26.053273, + "ave_all_frame_msssim": 0.829714, + "ave_all_frame_psnr_y": 24.655252, + "ave_all_frame_psnr_u": 29.054625, + "ave_all_frame_psnr_v": 31.440045, + "ave_all_frame_msssim_y": 0.819058, + "ave_all_frame_msssim_u": 0.847864, + "ave_all_frame_msssim_v": 0.875499, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC25_1920x1080_24.yuv" + } + }, + "videoSRC26_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.040465, + "ave_i_frame_psnr": 45.842465, + "ave_i_frame_msssim": 0.995544, + "ave_i_frame_psnr_y": 44.993769, + "ave_i_frame_psnr_u": 47.867254, + "ave_i_frame_psnr_v": 48.909855, + "ave_i_frame_msssim_y": 0.995431, + "ave_i_frame_msssim_u": 0.995528, + "ave_i_frame_msssim_v": 0.996241, + "test_time": 77680.377521, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.040465, + "ave_all_frame_psnr": 45.842465, + "ave_all_frame_msssim": 0.995544, + "ave_all_frame_psnr_y": 44.993769, + "ave_all_frame_psnr_u": 47.867254, + "ave_all_frame_psnr_v": 48.909855, + "ave_all_frame_msssim_y": 0.995431, + "ave_all_frame_msssim_u": 0.995528, + "ave_all_frame_msssim_v": 0.996241, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.026605, + "ave_i_frame_psnr": 44.831234, + "ave_i_frame_msssim": 0.994103, + "ave_i_frame_psnr_y": 43.960070, + "ave_i_frame_psnr_u": 47.017562, + "ave_i_frame_psnr_v": 47.871889, + "ave_i_frame_msssim_y": 0.993944, + "ave_i_frame_msssim_u": 0.994205, + "ave_i_frame_msssim_v": 0.994954, + "test_time": 59591.395367, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.026605, + "ave_all_frame_psnr": 44.831234, + "ave_all_frame_msssim": 0.994103, + "ave_all_frame_psnr_y": 43.960070, + "ave_all_frame_psnr_u": 47.017562, + "ave_all_frame_psnr_v": 47.871889, + "ave_all_frame_msssim_y": 0.993944, + "ave_all_frame_msssim_u": 0.994205, + "ave_all_frame_msssim_v": 0.994954, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017749, + "ave_i_frame_psnr": 43.617446, + "ave_i_frame_msssim": 0.991919, + "ave_i_frame_psnr_y": 42.687479, + "ave_i_frame_psnr_u": 46.065364, + "ave_i_frame_psnr_v": 46.749332, + "ave_i_frame_msssim_y": 0.991607, + "ave_i_frame_msssim_u": 0.992554, + "ave_i_frame_msssim_v": 0.993155, + "test_time": 44013.876024, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017749, + "ave_all_frame_psnr": 43.617446, + "ave_all_frame_msssim": 0.991919, + "ave_all_frame_psnr_y": 42.687479, + "ave_all_frame_psnr_u": 46.065364, + "ave_all_frame_psnr_v": 46.749332, + "ave_all_frame_msssim_y": 0.991607, + "ave_all_frame_msssim_u": 0.992554, + "ave_all_frame_msssim_v": 0.993155, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011991, + "ave_i_frame_psnr": 42.282641, + "ave_i_frame_msssim": 0.988731, + "ave_i_frame_psnr_y": 41.172934, + "ave_i_frame_psnr_u": 45.323893, + "ave_i_frame_psnr_v": 45.899634, + "ave_i_frame_msssim_y": 0.987969, + "ave_i_frame_msssim_u": 0.990707, + "ave_i_frame_msssim_v": 0.991326, + "test_time": 32474.229808, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011991, + "ave_all_frame_psnr": 42.282641, + "ave_all_frame_msssim": 0.988731, + "ave_all_frame_psnr_y": 41.172934, + "ave_all_frame_psnr_u": 45.323893, + "ave_all_frame_psnr_v": 45.899634, + "ave_all_frame_msssim_y": 0.987969, + "ave_all_frame_msssim_u": 0.990707, + "ave_all_frame_msssim_v": 0.991326, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008650, + "ave_i_frame_psnr": 40.998606, + "ave_i_frame_msssim": 0.984819, + "ave_i_frame_psnr_y": 39.795433, + "ave_i_frame_psnr_u": 44.362414, + "ave_i_frame_psnr_v": 44.853838, + "ave_i_frame_msssim_y": 0.983568, + "ave_i_frame_msssim_u": 0.988179, + "ave_i_frame_msssim_v": 0.988964, + "test_time": 24299.953546, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008650, + "ave_all_frame_psnr": 40.998606, + "ave_all_frame_msssim": 0.984819, + "ave_all_frame_psnr_y": 39.795433, + "ave_all_frame_psnr_u": 44.362414, + "ave_all_frame_psnr_v": 44.853838, + "ave_all_frame_msssim_y": 0.983568, + "ave_all_frame_msssim_u": 0.988179, + "ave_all_frame_msssim_v": 0.988964, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006242, + "ave_i_frame_psnr": 39.643423, + "ave_i_frame_msssim": 0.979406, + "ave_i_frame_psnr_y": 38.308280, + "ave_i_frame_psnr_u": 43.229400, + "ave_i_frame_psnr_v": 44.068302, + "ave_i_frame_msssim_y": 0.977433, + "ave_i_frame_msssim_u": 0.984125, + "ave_i_frame_msssim_v": 0.986527, + "test_time": 18912.623039, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006242, + "ave_all_frame_psnr": 39.643423, + "ave_all_frame_msssim": 0.979406, + "ave_all_frame_psnr_y": 38.308280, + "ave_all_frame_psnr_u": 43.229400, + "ave_all_frame_psnr_v": 44.068302, + "ave_all_frame_msssim_y": 0.977433, + "ave_all_frame_msssim_u": 0.984125, + "ave_all_frame_msssim_v": 0.986527, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004492, + "ave_i_frame_psnr": 38.203917, + "ave_i_frame_msssim": 0.972197, + "ave_i_frame_psnr_y": 36.742154, + "ave_i_frame_psnr_u": 42.180871, + "ave_i_frame_psnr_v": 42.997544, + "ave_i_frame_msssim_y": 0.969021, + "ave_i_frame_msssim_u": 0.980248, + "ave_i_frame_msssim_v": 0.983200, + "test_time": 14549.978100, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004492, + "ave_all_frame_psnr": 38.203917, + "ave_all_frame_msssim": 0.972197, + "ave_all_frame_psnr_y": 36.742154, + "ave_all_frame_psnr_u": 42.180871, + "ave_all_frame_psnr_v": 42.997544, + "ave_all_frame_msssim_y": 0.969021, + "ave_all_frame_msssim_u": 0.980248, + "ave_all_frame_msssim_v": 0.983200, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003219, + "ave_i_frame_psnr": 36.767200, + "ave_i_frame_msssim": 0.962650, + "ave_i_frame_psnr_y": 35.084236, + "ave_i_frame_psnr_u": 41.433948, + "ave_i_frame_psnr_v": 42.198237, + "ave_i_frame_msssim_y": 0.957381, + "ave_i_frame_msssim_u": 0.976919, + "ave_i_frame_msssim_v": 0.979998, + "test_time": 11326.378763, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003219, + "ave_all_frame_psnr": 36.767200, + "ave_all_frame_msssim": 0.962650, + "ave_all_frame_psnr_y": 35.084236, + "ave_all_frame_psnr_u": 41.433948, + "ave_all_frame_psnr_v": 42.198237, + "ave_all_frame_msssim_y": 0.957381, + "ave_all_frame_msssim_u": 0.976919, + "ave_all_frame_msssim_v": 0.979998, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002293, + "ave_i_frame_psnr": 35.096132, + "ave_i_frame_msssim": 0.948653, + "ave_i_frame_psnr_y": 33.342320, + "ave_i_frame_psnr_u": 39.792640, + "ave_i_frame_psnr_v": 40.922501, + "ave_i_frame_msssim_y": 0.940927, + "ave_i_frame_msssim_u": 0.969747, + "ave_i_frame_msssim_v": 0.973911, + "test_time": 8719.355085, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002293, + "ave_all_frame_psnr": 35.096132, + "ave_all_frame_msssim": 0.948653, + "ave_all_frame_psnr_y": 33.342320, + "ave_all_frame_psnr_u": 39.792640, + "ave_all_frame_psnr_v": 40.922501, + "ave_all_frame_msssim_y": 0.940927, + "ave_all_frame_msssim_u": 0.969747, + "ave_all_frame_msssim_v": 0.973911, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001639, + "ave_i_frame_psnr": 33.422280, + "ave_i_frame_msssim": 0.930798, + "ave_i_frame_psnr_y": 31.609417, + "ave_i_frame_psnr_u": 38.330776, + "ave_i_frame_psnr_v": 39.390962, + "ave_i_frame_msssim_y": 0.919676, + "ave_i_frame_msssim_u": 0.961013, + "ave_i_frame_msssim_v": 0.967309, + "test_time": 5901.266698, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001639, + "ave_all_frame_psnr": 33.422280, + "ave_all_frame_msssim": 0.930798, + "ave_all_frame_psnr_y": 31.609417, + "ave_all_frame_psnr_u": 38.330776, + "ave_all_frame_psnr_v": 39.390962, + "ave_all_frame_msssim_y": 0.919676, + "ave_all_frame_msssim_u": 0.961013, + "ave_all_frame_msssim_v": 0.967309, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC26_1920x1080_30.yuv" + } + }, + "videoSRC27_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.131505, + "ave_i_frame_psnr": 43.859593, + "ave_i_frame_msssim": 0.995129, + "ave_i_frame_psnr_y": 42.699440, + "ave_i_frame_psnr_u": 47.044798, + "ave_i_frame_psnr_v": 47.635310, + "ave_i_frame_msssim_y": 0.995523, + "ave_i_frame_msssim_u": 0.993768, + "ave_i_frame_msssim_v": 0.994122, + "test_time": 118976.869858, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.131505, + "ave_all_frame_psnr": 43.859593, + "ave_all_frame_msssim": 0.995129, + "ave_all_frame_psnr_y": 42.699440, + "ave_all_frame_psnr_u": 47.044798, + "ave_all_frame_psnr_v": 47.635310, + "ave_all_frame_msssim_y": 0.995523, + "ave_all_frame_msssim_u": 0.993768, + "ave_all_frame_msssim_v": 0.994122, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.080175, + "ave_i_frame_psnr": 41.963198, + "ave_i_frame_msssim": 0.992348, + "ave_i_frame_psnr_y": 40.513346, + "ave_i_frame_psnr_u": 45.766812, + "ave_i_frame_psnr_v": 46.858695, + "ave_i_frame_msssim_y": 0.992548, + "ave_i_frame_msssim_u": 0.990975, + "ave_i_frame_msssim_v": 0.992523, + "test_time": 98011.396091, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.080175, + "ave_all_frame_psnr": 41.963198, + "ave_all_frame_msssim": 0.992348, + "ave_all_frame_psnr_y": 40.513346, + "ave_all_frame_psnr_u": 45.766812, + "ave_all_frame_psnr_v": 46.858695, + "ave_all_frame_msssim_y": 0.992548, + "ave_all_frame_msssim_u": 0.990975, + "ave_all_frame_msssim_v": 0.992523, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.047393, + "ave_i_frame_psnr": 40.108819, + "ave_i_frame_msssim": 0.987962, + "ave_i_frame_psnr_y": 38.373036, + "ave_i_frame_psnr_u": 44.498369, + "ave_i_frame_psnr_v": 46.133967, + "ave_i_frame_msssim_y": 0.987611, + "ave_i_frame_msssim_u": 0.987197, + "ave_i_frame_msssim_v": 0.990831, + "test_time": 74803.735183, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.047393, + "ave_all_frame_psnr": 40.108819, + "ave_all_frame_msssim": 0.987962, + "ave_all_frame_psnr_y": 38.373036, + "ave_all_frame_psnr_u": 44.498369, + "ave_all_frame_psnr_v": 46.133967, + "ave_all_frame_msssim_y": 0.987611, + "ave_all_frame_msssim_u": 0.987197, + "ave_all_frame_msssim_v": 0.990831, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.027325, + "ave_i_frame_psnr": 38.367876, + "ave_i_frame_msssim": 0.981341, + "ave_i_frame_psnr_y": 36.337623, + "ave_i_frame_psnr_u": 43.357241, + "ave_i_frame_psnr_v": 45.560028, + "ave_i_frame_msssim_y": 0.979775, + "ave_i_frame_msssim_u": 0.982596, + "ave_i_frame_msssim_v": 0.989479, + "test_time": 54062.111823, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.027325, + "ave_all_frame_psnr": 38.367876, + "ave_all_frame_msssim": 0.981341, + "ave_all_frame_psnr_y": 36.337623, + "ave_all_frame_psnr_u": 43.357241, + "ave_all_frame_psnr_v": 45.560028, + "ave_all_frame_msssim_y": 0.979775, + "ave_all_frame_msssim_u": 0.982596, + "ave_all_frame_msssim_v": 0.989479, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017000, + "ave_i_frame_psnr": 36.917398, + "ave_i_frame_msssim": 0.973182, + "ave_i_frame_psnr_y": 34.714596, + "ave_i_frame_psnr_u": 42.209354, + "ave_i_frame_psnr_v": 44.842258, + "ave_i_frame_msssim_y": 0.970150, + "ave_i_frame_msssim_u": 0.976767, + "ave_i_frame_msssim_v": 0.987788, + "test_time": 41582.315130, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017000, + "ave_all_frame_psnr": 36.917398, + "ave_all_frame_msssim": 0.973182, + "ave_all_frame_psnr_y": 34.714596, + "ave_all_frame_psnr_u": 42.209354, + "ave_all_frame_psnr_v": 44.842258, + "ave_all_frame_msssim_y": 0.970150, + "ave_all_frame_msssim_u": 0.976767, + "ave_all_frame_msssim_v": 0.987788, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.010439, + "ave_i_frame_psnr": 35.645555, + "ave_i_frame_msssim": 0.962347, + "ave_i_frame_psnr_y": 33.159257, + "ave_i_frame_psnr_u": 41.572397, + "ave_i_frame_psnr_v": 44.636500, + "ave_i_frame_msssim_y": 0.956474, + "ave_i_frame_msssim_u": 0.972635, + "ave_i_frame_msssim_v": 0.987298, + "test_time": 30345.406096, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.010439, + "ave_all_frame_psnr": 35.645555, + "ave_all_frame_msssim": 0.962347, + "ave_all_frame_psnr_y": 33.159257, + "ave_all_frame_psnr_u": 41.572397, + "ave_all_frame_psnr_v": 44.636500, + "ave_all_frame_msssim_y": 0.956474, + "ave_all_frame_msssim_u": 0.972635, + "ave_all_frame_msssim_v": 0.987298, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006362, + "ave_i_frame_psnr": 34.357370, + "ave_i_frame_msssim": 0.947547, + "ave_i_frame_psnr_y": 31.651609, + "ave_i_frame_psnr_u": 40.824197, + "ave_i_frame_psnr_v": 44.125110, + "ave_i_frame_msssim_y": 0.937850, + "ave_i_frame_msssim_u": 0.967285, + "ave_i_frame_msssim_v": 0.985996, + "test_time": 22487.427191, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006362, + "ave_all_frame_psnr": 34.357370, + "ave_all_frame_msssim": 0.947547, + "ave_all_frame_psnr_y": 31.651609, + "ave_all_frame_psnr_u": 40.824197, + "ave_all_frame_psnr_v": 44.125110, + "ave_all_frame_msssim_y": 0.937850, + "ave_all_frame_msssim_u": 0.967285, + "ave_all_frame_msssim_v": 0.985996, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003880, + "ave_i_frame_psnr": 33.107417, + "ave_i_frame_msssim": 0.927723, + "ave_i_frame_psnr_y": 30.195968, + "ave_i_frame_psnr_u": 40.135141, + "ave_i_frame_psnr_v": 43.548391, + "ave_i_frame_msssim_y": 0.912618, + "ave_i_frame_msssim_u": 0.962196, + "ave_i_frame_msssim_v": 0.983879, + "test_time": 16516.429394, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003880, + "ave_all_frame_psnr": 33.107417, + "ave_all_frame_msssim": 0.927723, + "ave_all_frame_psnr_y": 30.195968, + "ave_all_frame_psnr_u": 40.135141, + "ave_all_frame_psnr_v": 43.548391, + "ave_all_frame_msssim_y": 0.912618, + "ave_all_frame_msssim_u": 0.962196, + "ave_all_frame_msssim_v": 0.983879, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002362, + "ave_i_frame_psnr": 31.773955, + "ave_i_frame_msssim": 0.902719, + "ave_i_frame_psnr_y": 28.796768, + "ave_i_frame_psnr_u": 38.943965, + "ave_i_frame_psnr_v": 42.467065, + "ave_i_frame_msssim_y": 0.880884, + "ave_i_frame_msssim_u": 0.952830, + "ave_i_frame_msssim_v": 0.983615, + "test_time": 12156.768780, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002362, + "ave_all_frame_psnr": 31.773955, + "ave_all_frame_msssim": 0.902719, + "ave_all_frame_psnr_y": 28.796768, + "ave_all_frame_psnr_u": 38.943965, + "ave_all_frame_psnr_v": 42.467065, + "ave_all_frame_msssim_y": 0.880884, + "ave_all_frame_msssim_u": 0.952830, + "ave_all_frame_msssim_v": 0.983615, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001448, + "ave_i_frame_psnr": 30.438976, + "ave_i_frame_msssim": 0.870311, + "ave_i_frame_psnr_y": 27.435311, + "ave_i_frame_psnr_u": 37.796835, + "ave_i_frame_psnr_v": 41.103106, + "ave_i_frame_msssim_y": 0.839956, + "ave_i_frame_msssim_u": 0.941155, + "ave_i_frame_msssim_v": 0.981596, + "test_time": 7084.168777, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001448, + "ave_all_frame_psnr": 30.438976, + "ave_all_frame_msssim": 0.870311, + "ave_all_frame_psnr_y": 27.435311, + "ave_all_frame_psnr_u": 37.796835, + "ave_all_frame_psnr_v": 41.103106, + "ave_all_frame_msssim_y": 0.839956, + "ave_all_frame_msssim_u": 0.941155, + "ave_all_frame_msssim_v": 0.981596, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC27_1920x1080_30.yuv" + } + }, + "videoSRC28_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017248, + "ave_i_frame_psnr": 45.034046, + "ave_i_frame_msssim": 0.995051, + "ave_i_frame_psnr_y": 44.053928, + "ave_i_frame_psnr_u": 47.491068, + "ave_i_frame_psnr_v": 48.457739, + "ave_i_frame_msssim_y": 0.994645, + "ave_i_frame_msssim_u": 0.996153, + "ave_i_frame_msssim_v": 0.996385, + "test_time": 46112.755479, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017248, + "ave_all_frame_psnr": 45.034046, + "ave_all_frame_msssim": 0.995051, + "ave_all_frame_psnr_y": 44.053928, + "ave_all_frame_psnr_u": 47.491068, + "ave_all_frame_psnr_v": 48.457739, + "ave_all_frame_msssim_y": 0.994645, + "ave_all_frame_msssim_u": 0.996153, + "ave_all_frame_msssim_v": 0.996385, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011118, + "ave_i_frame_psnr": 44.006647, + "ave_i_frame_msssim": 0.994043, + "ave_i_frame_psnr_y": 43.009125, + "ave_i_frame_psnr_u": 46.484535, + "ave_i_frame_psnr_v": 47.513889, + "ave_i_frame_msssim_y": 0.993696, + "ave_i_frame_msssim_u": 0.994906, + "ave_i_frame_msssim_v": 0.995262, + "test_time": 36021.845582, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011118, + "ave_all_frame_psnr": 44.006647, + "ave_all_frame_msssim": 0.994043, + "ave_all_frame_psnr_y": 43.009125, + "ave_all_frame_psnr_u": 46.484535, + "ave_all_frame_psnr_v": 47.513889, + "ave_all_frame_msssim_y": 0.993696, + "ave_all_frame_msssim_u": 0.994906, + "ave_all_frame_msssim_v": 0.995262, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007347, + "ave_i_frame_psnr": 42.765543, + "ave_i_frame_msssim": 0.992420, + "ave_i_frame_psnr_y": 41.713252, + "ave_i_frame_psnr_u": 45.372411, + "ave_i_frame_psnr_v": 46.472417, + "ave_i_frame_msssim_y": 0.992091, + "ave_i_frame_msssim_u": 0.993122, + "ave_i_frame_msssim_v": 0.993689, + "test_time": 26137.155791, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007347, + "ave_all_frame_psnr": 42.765543, + "ave_all_frame_msssim": 0.992420, + "ave_all_frame_psnr_y": 41.713252, + "ave_all_frame_psnr_u": 45.372411, + "ave_all_frame_psnr_v": 46.472417, + "ave_all_frame_msssim_y": 0.992091, + "ave_all_frame_msssim_u": 0.993122, + "ave_all_frame_msssim_v": 0.993689, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005027, + "ave_i_frame_psnr": 41.468156, + "ave_i_frame_msssim": 0.990235, + "ave_i_frame_psnr_y": 40.309566, + "ave_i_frame_psnr_u": 44.320135, + "ave_i_frame_psnr_v": 45.567719, + "ave_i_frame_msssim_y": 0.989776, + "ave_i_frame_msssim_u": 0.991045, + "ave_i_frame_msssim_v": 0.992175, + "test_time": 19327.668826, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005027, + "ave_all_frame_psnr": 41.468156, + "ave_all_frame_msssim": 0.990235, + "ave_all_frame_psnr_y": 40.309566, + "ave_all_frame_psnr_u": 44.320135, + "ave_all_frame_psnr_v": 45.567719, + "ave_all_frame_msssim_y": 0.989776, + "ave_all_frame_msssim_u": 0.991045, + "ave_all_frame_msssim_v": 0.992175, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003912, + "ave_i_frame_psnr": 40.144364, + "ave_i_frame_msssim": 0.987383, + "ave_i_frame_psnr_y": 38.876224, + "ave_i_frame_psnr_u": 43.161894, + "ave_i_frame_psnr_v": 44.735677, + "ave_i_frame_msssim_y": 0.986753, + "ave_i_frame_msssim_u": 0.988013, + "ave_i_frame_msssim_v": 0.990534, + "test_time": 15623.069221, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003912, + "ave_all_frame_psnr": 40.144364, + "ave_all_frame_msssim": 0.987383, + "ave_all_frame_psnr_y": 38.876224, + "ave_all_frame_psnr_u": 43.161894, + "ave_all_frame_psnr_v": 44.735677, + "ave_all_frame_msssim_y": 0.986753, + "ave_all_frame_msssim_u": 0.988013, + "ave_all_frame_msssim_v": 0.990534, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002761, + "ave_i_frame_psnr": 38.789977, + "ave_i_frame_msssim": 0.983452, + "ave_i_frame_psnr_y": 37.348707, + "ave_i_frame_psnr_u": 42.205487, + "ave_i_frame_psnr_v": 44.022083, + "ave_i_frame_msssim_y": 0.982184, + "ave_i_frame_msssim_u": 0.985627, + "ave_i_frame_msssim_v": 0.988881, + "test_time": 11952.672379, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002761, + "ave_all_frame_psnr": 38.789977, + "ave_all_frame_msssim": 0.983452, + "ave_all_frame_psnr_y": 37.348707, + "ave_all_frame_psnr_u": 42.205487, + "ave_all_frame_psnr_v": 44.022083, + "ave_all_frame_msssim_y": 0.982184, + "ave_all_frame_msssim_u": 0.985627, + "ave_all_frame_msssim_v": 0.988881, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001954, + "ave_i_frame_psnr": 37.419643, + "ave_i_frame_msssim": 0.978058, + "ave_i_frame_psnr_y": 35.810661, + "ave_i_frame_psnr_u": 41.214632, + "ave_i_frame_psnr_v": 43.278546, + "ave_i_frame_msssim_y": 0.976004, + "ave_i_frame_msssim_u": 0.981794, + "ave_i_frame_msssim_v": 0.986645, + "test_time": 9337.569979, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001954, + "ave_all_frame_psnr": 37.419643, + "ave_all_frame_msssim": 0.978058, + "ave_all_frame_psnr_y": 35.810661, + "ave_all_frame_psnr_u": 41.214632, + "ave_all_frame_psnr_v": 43.278546, + "ave_all_frame_msssim_y": 0.976004, + "ave_all_frame_msssim_u": 0.981794, + "ave_all_frame_msssim_v": 0.986645, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001369, + "ave_i_frame_psnr": 36.016985, + "ave_i_frame_msssim": 0.970710, + "ave_i_frame_psnr_y": 34.205360, + "ave_i_frame_psnr_u": 40.244539, + "ave_i_frame_psnr_v": 42.659185, + "ave_i_frame_msssim_y": 0.967179, + "ave_i_frame_msssim_u": 0.978052, + "ave_i_frame_msssim_v": 0.984559, + "test_time": 7408.341439, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001369, + "ave_all_frame_psnr": 36.016985, + "ave_all_frame_msssim": 0.970710, + "ave_all_frame_psnr_y": 34.205360, + "ave_all_frame_psnr_u": 40.244539, + "ave_all_frame_psnr_v": 42.659185, + "ave_all_frame_msssim_y": 0.967179, + "ave_all_frame_msssim_u": 0.978052, + "ave_all_frame_msssim_v": 0.984559, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000961, + "ave_i_frame_psnr": 34.481116, + "ave_i_frame_msssim": 0.960553, + "ave_i_frame_psnr_y": 32.625267, + "ave_i_frame_psnr_u": 38.842186, + "ave_i_frame_psnr_v": 41.255135, + "ave_i_frame_msssim_y": 0.955619, + "ave_i_frame_msssim_u": 0.970242, + "ave_i_frame_msssim_v": 0.980469, + "test_time": 5952.486252, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000961, + "ave_all_frame_psnr": 34.481116, + "ave_all_frame_msssim": 0.960553, + "ave_all_frame_psnr_y": 32.625267, + "ave_all_frame_psnr_u": 38.842186, + "ave_all_frame_psnr_v": 41.255135, + "ave_all_frame_msssim_y": 0.955619, + "ave_all_frame_msssim_u": 0.970242, + "ave_all_frame_msssim_v": 0.980469, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000668, + "ave_i_frame_psnr": 33.033272, + "ave_i_frame_msssim": 0.948301, + "ave_i_frame_psnr_y": 31.074706, + "ave_i_frame_psnr_u": 37.740254, + "ave_i_frame_psnr_v": 40.077688, + "ave_i_frame_msssim_y": 0.941161, + "ave_i_frame_msssim_u": 0.963515, + "ave_i_frame_msssim_v": 0.975927, + "test_time": 4379.567741, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000668, + "ave_all_frame_psnr": 33.033272, + "ave_all_frame_msssim": 0.948301, + "ave_all_frame_psnr_y": 31.074706, + "ave_all_frame_psnr_u": 37.740254, + "ave_all_frame_psnr_v": 40.077688, + "ave_all_frame_msssim_y": 0.941161, + "ave_all_frame_msssim_u": 0.963515, + "ave_all_frame_msssim_v": 0.975927, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC28_1920x1080_30.yuv" + } + }, + "videoSRC29_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003445, + "ave_i_frame_psnr": 48.181782, + "ave_i_frame_msssim": 0.995614, + "ave_i_frame_psnr_y": 46.891368, + "ave_i_frame_psnr_u": 52.603863, + "ave_i_frame_psnr_v": 51.502186, + "ave_i_frame_msssim_y": 0.994852, + "ave_i_frame_msssim_u": 0.998166, + "ave_i_frame_msssim_v": 0.997637, + "test_time": 14564.017950, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003445, + "ave_all_frame_psnr": 48.181782, + "ave_all_frame_msssim": 0.995614, + "ave_all_frame_psnr_y": 46.891368, + "ave_all_frame_psnr_u": 52.603863, + "ave_all_frame_psnr_v": 51.502186, + "ave_all_frame_msssim_y": 0.994852, + "ave_all_frame_msssim_u": 0.998166, + "ave_all_frame_msssim_v": 0.997637, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002087, + "ave_i_frame_psnr": 47.504125, + "ave_i_frame_msssim": 0.994494, + "ave_i_frame_psnr_y": 46.230613, + "ave_i_frame_psnr_u": 51.815685, + "ave_i_frame_psnr_v": 50.833638, + "ave_i_frame_msssim_y": 0.993520, + "ave_i_frame_msssim_u": 0.997716, + "ave_i_frame_msssim_v": 0.997117, + "test_time": 10933.391809, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002087, + "ave_all_frame_psnr": 47.504125, + "ave_all_frame_msssim": 0.994494, + "ave_all_frame_psnr_y": 46.230613, + "ave_all_frame_psnr_u": 51.815685, + "ave_all_frame_psnr_v": 50.833638, + "ave_all_frame_msssim_y": 0.993520, + "ave_all_frame_msssim_u": 0.997716, + "ave_all_frame_msssim_v": 0.997117, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001332, + "ave_i_frame_psnr": 46.708101, + "ave_i_frame_msssim": 0.992893, + "ave_i_frame_psnr_y": 45.431351, + "ave_i_frame_psnr_u": 50.912290, + "ave_i_frame_psnr_v": 50.164411, + "ave_i_frame_msssim_y": 0.991573, + "ave_i_frame_msssim_u": 0.997135, + "ave_i_frame_msssim_v": 0.996571, + "test_time": 8172.511451, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001332, + "ave_all_frame_psnr": 46.708101, + "ave_all_frame_msssim": 0.992893, + "ave_all_frame_psnr_y": 45.431351, + "ave_all_frame_psnr_u": 50.912290, + "ave_all_frame_psnr_v": 50.164411, + "ave_all_frame_msssim_y": 0.991573, + "ave_all_frame_msssim_u": 0.997135, + "ave_all_frame_msssim_v": 0.996571, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000869, + "ave_i_frame_psnr": 45.791318, + "ave_i_frame_msssim": 0.990703, + "ave_i_frame_psnr_y": 44.536463, + "ave_i_frame_psnr_u": 49.869161, + "ave_i_frame_psnr_v": 49.242599, + "ave_i_frame_msssim_y": 0.988942, + "ave_i_frame_msssim_u": 0.996336, + "ave_i_frame_msssim_v": 0.995642, + "test_time": 6122.453170, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000869, + "ave_all_frame_psnr": 45.791318, + "ave_all_frame_msssim": 0.990703, + "ave_all_frame_psnr_y": 44.536463, + "ave_all_frame_psnr_u": 49.869161, + "ave_all_frame_psnr_v": 49.242599, + "ave_all_frame_msssim_y": 0.988942, + "ave_all_frame_msssim_u": 0.996336, + "ave_all_frame_msssim_v": 0.995642, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000602, + "ave_i_frame_psnr": 44.733192, + "ave_i_frame_msssim": 0.987611, + "ave_i_frame_psnr_y": 43.512138, + "ave_i_frame_psnr_u": 48.589381, + "ave_i_frame_psnr_v": 48.203325, + "ave_i_frame_msssim_y": 0.985212, + "ave_i_frame_msssim_u": 0.994999, + "ave_i_frame_msssim_v": 0.994618, + "test_time": 4825.659344, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000602, + "ave_all_frame_psnr": 44.733192, + "ave_all_frame_msssim": 0.987611, + "ave_all_frame_psnr_y": 43.512138, + "ave_all_frame_psnr_u": 48.589381, + "ave_all_frame_psnr_v": 48.203325, + "ave_all_frame_msssim_y": 0.985212, + "ave_all_frame_msssim_u": 0.994999, + "ave_all_frame_msssim_v": 0.994618, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000427, + "ave_i_frame_psnr": 43.712567, + "ave_i_frame_msssim": 0.983802, + "ave_i_frame_psnr_y": 42.408692, + "ave_i_frame_psnr_u": 47.665260, + "ave_i_frame_psnr_v": 47.583120, + "ave_i_frame_msssim_y": 0.980425, + "ave_i_frame_msssim_u": 0.994054, + "ave_i_frame_msssim_v": 0.993812, + "test_time": 3861.615205, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000427, + "ave_all_frame_psnr": 43.712567, + "ave_all_frame_msssim": 0.983802, + "ave_all_frame_psnr_y": 42.408692, + "ave_all_frame_psnr_u": 47.665260, + "ave_all_frame_psnr_v": 47.583120, + "ave_all_frame_msssim_y": 0.980425, + "ave_all_frame_msssim_u": 0.994054, + "ave_all_frame_msssim_v": 0.993812, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000308, + "ave_i_frame_psnr": 42.683720, + "ave_i_frame_msssim": 0.979116, + "ave_i_frame_psnr_y": 41.303942, + "ave_i_frame_psnr_u": 47.007889, + "ave_i_frame_psnr_v": 46.638224, + "ave_i_frame_msssim_y": 0.974655, + "ave_i_frame_msssim_u": 0.992639, + "ave_i_frame_msssim_v": 0.992360, + "test_time": 3189.882658, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000308, + "ave_all_frame_psnr": 42.683720, + "ave_all_frame_msssim": 0.979116, + "ave_all_frame_psnr_y": 41.303942, + "ave_all_frame_psnr_u": 47.007889, + "ave_all_frame_psnr_v": 46.638224, + "ave_all_frame_msssim_y": 0.974655, + "ave_all_frame_msssim_u": 0.992639, + "ave_all_frame_msssim_v": 0.992360, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000227, + "ave_i_frame_psnr": 41.615454, + "ave_i_frame_msssim": 0.973227, + "ave_i_frame_psnr_y": 40.089640, + "ave_i_frame_psnr_u": 46.405797, + "ave_i_frame_psnr_v": 45.979997, + "ave_i_frame_msssim_y": 0.967297, + "ave_i_frame_msssim_u": 0.991048, + "ave_i_frame_msssim_v": 0.990982, + "test_time": 2777.711915, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000227, + "ave_all_frame_psnr": 41.615454, + "ave_all_frame_msssim": 0.973227, + "ave_all_frame_psnr_y": 40.089640, + "ave_all_frame_psnr_u": 46.405797, + "ave_all_frame_psnr_v": 45.979997, + "ave_all_frame_msssim_y": 0.967297, + "ave_all_frame_msssim_u": 0.991048, + "ave_all_frame_msssim_v": 0.990982, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000176, + "ave_i_frame_psnr": 40.313562, + "ave_i_frame_msssim": 0.966239, + "ave_i_frame_psnr_y": 38.908468, + "ave_i_frame_psnr_u": 44.486923, + "ave_i_frame_psnr_v": 44.570764, + "ave_i_frame_msssim_y": 0.958803, + "ave_i_frame_msssim_u": 0.988630, + "ave_i_frame_msssim_v": 0.988464, + "test_time": 2595.212722, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000176, + "ave_all_frame_psnr": 40.313562, + "ave_all_frame_msssim": 0.966239, + "ave_all_frame_psnr_y": 38.908468, + "ave_all_frame_psnr_u": 44.486923, + "ave_all_frame_psnr_v": 44.570764, + "ave_all_frame_msssim_y": 0.958803, + "ave_all_frame_msssim_u": 0.988630, + "ave_all_frame_msssim_v": 0.988464, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 120, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000133, + "ave_i_frame_psnr": 38.870428, + "ave_i_frame_msssim": 0.957097, + "ave_i_frame_psnr_y": 37.593330, + "ave_i_frame_psnr_u": 43.141382, + "ave_i_frame_psnr_v": 42.262061, + "ave_i_frame_msssim_y": 0.948056, + "ave_i_frame_msssim_u": 0.984056, + "ave_i_frame_msssim_v": 0.984383, + "test_time": 2338.119594, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000133, + "ave_all_frame_psnr": 38.870428, + "ave_all_frame_msssim": 0.957097, + "ave_all_frame_psnr_y": 37.593330, + "ave_all_frame_psnr_u": 43.141382, + "ave_all_frame_psnr_v": 42.262061, + "ave_all_frame_msssim_y": 0.948056, + "ave_all_frame_msssim_u": 0.984056, + "ave_all_frame_msssim_v": 0.984383, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC29_1920x1080_24.yuv" + } + }, + "videoSRC30_1920x1080_30.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012696, + "ave_i_frame_psnr": 43.212154, + "ave_i_frame_msssim": 0.994088, + "ave_i_frame_psnr_y": 42.418892, + "ave_i_frame_psnr_u": 43.798274, + "ave_i_frame_psnr_v": 47.385602, + "ave_i_frame_msssim_y": 0.993941, + "ave_i_frame_msssim_u": 0.992554, + "ave_i_frame_msssim_v": 0.996508, + "test_time": 34049.879100, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012696, + "ave_all_frame_psnr": 43.212154, + "ave_all_frame_msssim": 0.994088, + "ave_all_frame_psnr_y": 42.418892, + "ave_all_frame_psnr_u": 43.798274, + "ave_all_frame_psnr_v": 47.385602, + "ave_all_frame_msssim_y": 0.993941, + "ave_all_frame_msssim_u": 0.992554, + "ave_all_frame_msssim_v": 0.996508, + "qp": 22, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005939, + "ave_i_frame_psnr": 42.562833, + "ave_i_frame_msssim": 0.992711, + "ave_i_frame_psnr_y": 41.759632, + "ave_i_frame_psnr_u": 43.330371, + "ave_i_frame_psnr_v": 46.614499, + "ave_i_frame_msssim_y": 0.992488, + "ave_i_frame_msssim_u": 0.991156, + "ave_i_frame_msssim_v": 0.995603, + "test_time": 22203.335407, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005939, + "ave_all_frame_psnr": 42.562833, + "ave_all_frame_msssim": 0.992711, + "ave_all_frame_psnr_y": 41.759632, + "ave_all_frame_psnr_u": 43.330371, + "ave_all_frame_psnr_v": 46.614499, + "ave_all_frame_msssim_y": 0.992488, + "ave_all_frame_msssim_u": 0.991156, + "ave_all_frame_msssim_v": 0.995603, + "qp": 25, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003502, + "ave_i_frame_psnr": 41.835928, + "ave_i_frame_msssim": 0.990769, + "ave_i_frame_psnr_y": 41.034278, + "ave_i_frame_psnr_u": 42.765379, + "ave_i_frame_psnr_v": 45.716383, + "ave_i_frame_msssim_y": 0.990471, + "ave_i_frame_msssim_u": 0.989065, + "ave_i_frame_msssim_v": 0.994260, + "test_time": 15784.742998, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003502, + "ave_all_frame_psnr": 41.835928, + "ave_all_frame_msssim": 0.990769, + "ave_all_frame_psnr_y": 41.034278, + "ave_all_frame_psnr_u": 42.765379, + "ave_all_frame_psnr_v": 45.716383, + "ave_all_frame_msssim_y": 0.990471, + "ave_all_frame_msssim_u": 0.989065, + "ave_all_frame_msssim_v": 0.994260, + "qp": 28, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002267, + "ave_i_frame_psnr": 40.991164, + "ave_i_frame_msssim": 0.987990, + "ave_i_frame_psnr_y": 40.172156, + "ave_i_frame_psnr_u": 42.136369, + "ave_i_frame_psnr_v": 44.760005, + "ave_i_frame_msssim_y": 0.987496, + "ave_i_frame_msssim_u": 0.986582, + "ave_i_frame_msssim_v": 0.992361, + "test_time": 11938.487609, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002267, + "ave_all_frame_psnr": 40.991164, + "ave_all_frame_msssim": 0.987990, + "ave_all_frame_psnr_y": 40.172156, + "ave_all_frame_psnr_u": 42.136369, + "ave_all_frame_psnr_v": 44.760005, + "ave_all_frame_msssim_y": 0.987496, + "ave_all_frame_msssim_u": 0.986582, + "ave_all_frame_msssim_v": 0.992361, + "qp": 31, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001565, + "ave_i_frame_psnr": 40.044020, + "ave_i_frame_msssim": 0.984087, + "ave_i_frame_psnr_y": 39.193265, + "ave_i_frame_psnr_u": 41.466936, + "ave_i_frame_psnr_v": 43.725631, + "ave_i_frame_msssim_y": 0.983169, + "ave_i_frame_msssim_u": 0.983697, + "ave_i_frame_msssim_v": 0.989984, + "test_time": 9494.194076, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001565, + "ave_all_frame_psnr": 40.044020, + "ave_all_frame_msssim": 0.984087, + "ave_all_frame_psnr_y": 39.193265, + "ave_all_frame_psnr_u": 41.466936, + "ave_all_frame_psnr_v": 43.725631, + "ave_all_frame_msssim_y": 0.983169, + "ave_all_frame_msssim_u": 0.983697, + "ave_all_frame_msssim_v": 0.989984, + "qp": 34, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001102, + "ave_i_frame_psnr": 38.995185, + "ave_i_frame_msssim": 0.978565, + "ave_i_frame_psnr_y": 38.092158, + "ave_i_frame_psnr_u": 40.863747, + "ave_i_frame_psnr_v": 42.544790, + "ave_i_frame_msssim_y": 0.976992, + "ave_i_frame_msssim_u": 0.980578, + "ave_i_frame_msssim_v": 0.985988, + "test_time": 7554.637034, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001102, + "ave_all_frame_psnr": 38.995185, + "ave_all_frame_msssim": 0.978565, + "ave_all_frame_psnr_y": 38.092158, + "ave_all_frame_psnr_u": 40.863747, + "ave_all_frame_psnr_v": 42.544790, + "ave_all_frame_msssim_y": 0.976992, + "ave_all_frame_msssim_u": 0.980578, + "ave_all_frame_msssim_v": 0.985988, + "qp": 37, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000789, + "ave_i_frame_psnr": 37.959137, + "ave_i_frame_msssim": 0.971990, + "ave_i_frame_psnr_y": 36.954936, + "ave_i_frame_psnr_u": 40.174687, + "ave_i_frame_psnr_v": 41.768798, + "ave_i_frame_msssim_y": 0.969245, + "ave_i_frame_msssim_u": 0.977129, + "ave_i_frame_msssim_v": 0.983324, + "test_time": 5844.954067, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000789, + "ave_all_frame_psnr": 37.959137, + "ave_all_frame_msssim": 0.971990, + "ave_all_frame_psnr_y": 36.954936, + "ave_all_frame_psnr_u": 40.174687, + "ave_all_frame_psnr_v": 41.768798, + "ave_all_frame_msssim_y": 0.969245, + "ave_all_frame_msssim_u": 0.977129, + "ave_all_frame_msssim_v": 0.983324, + "qp": 40, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000567, + "ave_i_frame_psnr": 36.916153, + "ave_i_frame_msssim": 0.963843, + "ave_i_frame_psnr_y": 35.723287, + "ave_i_frame_psnr_u": 39.846528, + "ave_i_frame_psnr_v": 41.142972, + "ave_i_frame_msssim_y": 0.959152, + "ave_i_frame_msssim_u": 0.975109, + "ave_i_frame_msssim_v": 0.980726, + "test_time": 4788.378983, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000567, + "ave_all_frame_psnr": 36.916153, + "ave_all_frame_msssim": 0.963843, + "ave_all_frame_psnr_y": 35.723287, + "ave_all_frame_psnr_u": 39.846528, + "ave_all_frame_psnr_v": 41.142972, + "ave_all_frame_msssim_y": 0.959152, + "ave_all_frame_msssim_u": 0.975109, + "ave_all_frame_msssim_v": 0.980726, + "qp": 43, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000405, + "ave_i_frame_psnr": 35.606739, + "ave_i_frame_msssim": 0.951893, + "ave_i_frame_psnr_y": 34.379890, + "ave_i_frame_psnr_u": 38.645400, + "ave_i_frame_psnr_v": 39.929174, + "ave_i_frame_msssim_y": 0.945299, + "ave_i_frame_msssim_u": 0.967566, + "ave_i_frame_msssim_v": 0.975782, + "test_time": 4152.349759, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000405, + "ave_all_frame_psnr": 35.606739, + "ave_all_frame_msssim": 0.951893, + "ave_all_frame_psnr_y": 34.379890, + "ave_all_frame_psnr_u": 38.645400, + "ave_all_frame_psnr_v": 39.929174, + "ave_all_frame_msssim_y": 0.945299, + "ave_all_frame_msssim_u": 0.967566, + "ave_all_frame_msssim_v": 0.975782, + "qp": 46, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 150, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000291, + "ave_i_frame_psnr": 34.298630, + "ave_i_frame_msssim": 0.938135, + "ave_i_frame_psnr_y": 33.056508, + "ave_i_frame_psnr_u": 37.563562, + "ave_i_frame_psnr_v": 38.486433, + "ave_i_frame_msssim_y": 0.929475, + "ave_i_frame_msssim_u": 0.959322, + "ave_i_frame_msssim_v": 0.968909, + "test_time": 3264.554779, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000291, + "ave_all_frame_psnr": 34.298630, + "ave_all_frame_msssim": 0.938135, + "ave_all_frame_psnr_y": 33.056508, + "ave_all_frame_psnr_u": 37.563562, + "ave_all_frame_psnr_v": 38.486433, + "ave_all_frame_msssim_y": 0.929475, + "ave_all_frame_msssim_u": 0.959322, + "ave_all_frame_msssim_v": 0.968909, + "qp": 49, + "ds_name": "MCL-JCV", + "seq_name": "videoSRC30_1920x1080_30.yuv" + } + } + }, + "HEVC_B": { + "BQTerrace_1920x1080_60.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.285800, + "ave_i_frame_psnr": 39.105063, + "ave_i_frame_msssim": 0.989609, + "ave_i_frame_psnr_y": 37.784362, + "ave_i_frame_psnr_u": 41.938444, + "ave_i_frame_psnr_v": 44.195891, + "ave_i_frame_msssim_y": 0.989235, + "ave_i_frame_msssim_u": 0.989066, + "ave_i_frame_msssim_v": 0.992393, + "test_time": 527563.798756, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.285800, + "ave_all_frame_psnr": 39.105063, + "ave_all_frame_msssim": 0.989609, + "ave_all_frame_psnr_y": 37.784362, + "ave_all_frame_psnr_u": 41.938444, + "ave_all_frame_psnr_v": 44.195891, + "ave_all_frame_msssim_y": 0.989235, + "ave_all_frame_msssim_u": 0.989066, + "ave_all_frame_msssim_v": 0.992393, + "qp": 22, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.060786, + "ave_i_frame_psnr": 37.578083, + "ave_i_frame_msssim": 0.986358, + "ave_i_frame_psnr_y": 35.930072, + "ave_i_frame_psnr_u": 41.316365, + "ave_i_frame_psnr_v": 43.727866, + "ave_i_frame_msssim_y": 0.985536, + "ave_i_frame_msssim_u": 0.986606, + "ave_i_frame_msssim_v": 0.991042, + "test_time": 277231.377609, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.060786, + "ave_all_frame_psnr": 37.578083, + "ave_all_frame_msssim": 0.986358, + "ave_all_frame_psnr_y": 35.930072, + "ave_all_frame_psnr_u": 41.316365, + "ave_all_frame_psnr_v": 43.727866, + "ave_all_frame_msssim_y": 0.985536, + "ave_all_frame_msssim_u": 0.986606, + "ave_all_frame_msssim_v": 0.991042, + "qp": 25, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.023952, + "ave_i_frame_psnr": 36.699769, + "ave_i_frame_msssim": 0.983049, + "ave_i_frame_psnr_y": 34.958679, + "ave_i_frame_psnr_u": 40.660604, + "ave_i_frame_psnr_v": 43.185479, + "ave_i_frame_msssim_y": 0.981986, + "ave_i_frame_msssim_u": 0.983301, + "ave_i_frame_msssim_v": 0.989176, + "test_time": 165333.418104, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.023952, + "ave_all_frame_psnr": 36.699769, + "ave_all_frame_msssim": 0.983049, + "ave_all_frame_psnr_y": 34.958679, + "ave_all_frame_psnr_u": 40.660604, + "ave_all_frame_psnr_v": 43.185479, + "ave_all_frame_msssim_y": 0.981986, + "ave_all_frame_msssim_u": 0.983301, + "ave_all_frame_msssim_v": 0.989176, + "qp": 28, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012110, + "ave_i_frame_psnr": 35.739175, + "ave_i_frame_msssim": 0.978533, + "ave_i_frame_psnr_y": 33.909812, + "ave_i_frame_psnr_u": 39.947353, + "ave_i_frame_psnr_v": 42.507174, + "ave_i_frame_msssim_y": 0.977201, + "ave_i_frame_msssim_u": 0.978757, + "ave_i_frame_msssim_v": 0.986298, + "test_time": 120062.108924, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012110, + "ave_all_frame_psnr": 35.739175, + "ave_all_frame_msssim": 0.978533, + "ave_all_frame_psnr_y": 33.909812, + "ave_all_frame_psnr_u": 39.947353, + "ave_all_frame_psnr_v": 42.507174, + "ave_all_frame_msssim_y": 0.977201, + "ave_all_frame_msssim_u": 0.978757, + "ave_all_frame_msssim_v": 0.986298, + "qp": 31, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007098, + "ave_i_frame_psnr": 34.735979, + "ave_i_frame_msssim": 0.972738, + "ave_i_frame_psnr_y": 32.819273, + "ave_i_frame_psnr_u": 39.104387, + "ave_i_frame_psnr_v": 41.867810, + "ave_i_frame_msssim_y": 0.971118, + "ave_i_frame_msssim_u": 0.972021, + "ave_i_frame_msssim_v": 0.983178, + "test_time": 99280.342564, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007098, + "ave_all_frame_psnr": 34.735979, + "ave_all_frame_msssim": 0.972738, + "ave_all_frame_psnr_y": 32.819273, + "ave_all_frame_psnr_u": 39.104387, + "ave_all_frame_psnr_v": 41.867810, + "ave_all_frame_msssim_y": 0.971118, + "ave_all_frame_msssim_u": 0.972021, + "ave_all_frame_msssim_v": 0.983178, + "qp": 34, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004303, + "ave_i_frame_psnr": 33.640583, + "ave_i_frame_msssim": 0.965290, + "ave_i_frame_psnr_y": 31.632006, + "ave_i_frame_psnr_u": 38.204934, + "ave_i_frame_psnr_v": 41.127699, + "ave_i_frame_msssim_y": 0.962730, + "ave_i_frame_msssim_u": 0.966395, + "ave_i_frame_msssim_v": 0.979543, + "test_time": 79715.584309, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004303, + "ave_all_frame_psnr": 33.640583, + "ave_all_frame_msssim": 0.965290, + "ave_all_frame_psnr_y": 31.632006, + "ave_all_frame_psnr_u": 38.204934, + "ave_all_frame_psnr_v": 41.127699, + "ave_all_frame_msssim_y": 0.962730, + "ave_all_frame_msssim_u": 0.966395, + "ave_all_frame_msssim_v": 0.979543, + "qp": 37, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002653, + "ave_i_frame_psnr": 32.557066, + "ave_i_frame_msssim": 0.955485, + "ave_i_frame_psnr_y": 30.355026, + "ave_i_frame_psnr_u": 37.633457, + "ave_i_frame_psnr_v": 40.692921, + "ave_i_frame_msssim_y": 0.951273, + "ave_i_frame_msssim_u": 0.959785, + "ave_i_frame_msssim_v": 0.976456, + "test_time": 63785.661585, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002653, + "ave_all_frame_psnr": 32.557066, + "ave_all_frame_msssim": 0.955485, + "ave_all_frame_psnr_y": 30.355026, + "ave_all_frame_psnr_u": 37.633457, + "ave_all_frame_psnr_v": 40.692921, + "ave_all_frame_msssim_y": 0.951273, + "ave_all_frame_msssim_u": 0.959785, + "ave_all_frame_msssim_v": 0.976456, + "qp": 40, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001656, + "ave_i_frame_psnr": 31.425647, + "ave_i_frame_msssim": 0.942742, + "ave_i_frame_psnr_y": 29.001316, + "ave_i_frame_psnr_u": 37.218668, + "ave_i_frame_psnr_v": 40.178614, + "ave_i_frame_msssim_y": 0.935697, + "ave_i_frame_msssim_u": 0.954456, + "ave_i_frame_msssim_v": 0.973296, + "test_time": 50009.426445, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001656, + "ave_all_frame_psnr": 31.425647, + "ave_all_frame_msssim": 0.942742, + "ave_all_frame_psnr_y": 29.001316, + "ave_all_frame_psnr_u": 37.218668, + "ave_all_frame_psnr_v": 40.178614, + "ave_all_frame_msssim_y": 0.935697, + "ave_all_frame_msssim_u": 0.954456, + "ave_all_frame_msssim_v": 0.973296, + "qp": 43, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001042, + "ave_i_frame_psnr": 30.221130, + "ave_i_frame_msssim": 0.924305, + "ave_i_frame_psnr_y": 27.596044, + "ave_i_frame_psnr_u": 36.591594, + "ave_i_frame_psnr_v": 39.601178, + "ave_i_frame_msssim_y": 0.913372, + "ave_i_frame_msssim_u": 0.945854, + "ave_i_frame_msssim_v": 0.968351, + "test_time": 40167.858897, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001042, + "ave_all_frame_psnr": 30.221130, + "ave_all_frame_msssim": 0.924305, + "ave_all_frame_psnr_y": 27.596044, + "ave_all_frame_psnr_u": 36.591594, + "ave_all_frame_psnr_v": 39.601178, + "ave_all_frame_msssim_y": 0.913372, + "ave_all_frame_msssim_u": 0.945854, + "ave_all_frame_msssim_v": 0.968351, + "qp": 46, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000674, + "ave_i_frame_psnr": 28.992283, + "ave_i_frame_msssim": 0.900124, + "ave_i_frame_psnr_y": 26.201782, + "ave_i_frame_psnr_u": 35.706314, + "ave_i_frame_psnr_v": 39.021258, + "ave_i_frame_msssim_y": 0.884515, + "ave_i_frame_msssim_u": 0.931162, + "ave_i_frame_msssim_v": 0.962740, + "test_time": 33118.586561, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000674, + "ave_all_frame_psnr": 28.992283, + "ave_all_frame_msssim": 0.900124, + "ave_all_frame_psnr_y": 26.201782, + "ave_all_frame_psnr_u": 35.706314, + "ave_all_frame_psnr_v": 39.021258, + "ave_all_frame_msssim_y": 0.884515, + "ave_all_frame_msssim_u": 0.931162, + "ave_all_frame_msssim_v": 0.962740, + "qp": 49, + "ds_name": "HEVC_B", + "seq_name": "BQTerrace_1920x1080_60.yuv" + } + }, + "BasketballDrive_1920x1080_50.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.135275, + "ave_i_frame_psnr": 40.688221, + "ave_i_frame_msssim": 0.991232, + "ave_i_frame_psnr_y": 39.434589, + "ave_i_frame_psnr_u": 43.791905, + "ave_i_frame_psnr_v": 45.106331, + "ave_i_frame_msssim_y": 0.990331, + "ave_i_frame_msssim_u": 0.992803, + "ave_i_frame_msssim_v": 0.995069, + "test_time": 461585.392666, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.135275, + "ave_all_frame_psnr": 40.688221, + "ave_all_frame_msssim": 0.991232, + "ave_all_frame_psnr_y": 39.434589, + "ave_all_frame_psnr_u": 43.791905, + "ave_all_frame_psnr_v": 45.106331, + "ave_all_frame_msssim_y": 0.990331, + "ave_all_frame_msssim_u": 0.992803, + "ave_all_frame_msssim_v": 0.995069, + "qp": 22, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.066119, + "ave_i_frame_psnr": 39.617369, + "ave_i_frame_msssim": 0.988327, + "ave_i_frame_psnr_y": 38.344042, + "ave_i_frame_psnr_u": 43.024812, + "ave_i_frame_psnr_v": 43.849889, + "ave_i_frame_msssim_y": 0.987110, + "ave_i_frame_msssim_u": 0.990749, + "ave_i_frame_msssim_v": 0.993205, + "test_time": 311988.311746, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.066119, + "ave_all_frame_psnr": 39.617369, + "ave_all_frame_msssim": 0.988327, + "ave_all_frame_psnr_y": 38.344042, + "ave_all_frame_psnr_u": 43.024812, + "ave_all_frame_psnr_v": 43.849889, + "ave_all_frame_msssim_y": 0.987110, + "ave_all_frame_msssim_u": 0.990749, + "ave_all_frame_msssim_v": 0.993205, + "qp": 25, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.038683, + "ave_i_frame_psnr": 38.560272, + "ave_i_frame_msssim": 0.984347, + "ave_i_frame_psnr_y": 37.288700, + "ave_i_frame_psnr_u": 42.187651, + "ave_i_frame_psnr_v": 42.562325, + "ave_i_frame_msssim_y": 0.982689, + "ave_i_frame_msssim_u": 0.988037, + "ave_i_frame_msssim_v": 0.990604, + "test_time": 223751.999995, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.038683, + "ave_all_frame_psnr": 38.560272, + "ave_all_frame_msssim": 0.984347, + "ave_all_frame_psnr_y": 37.288700, + "ave_all_frame_psnr_u": 42.187651, + "ave_all_frame_psnr_v": 42.562325, + "ave_all_frame_msssim_y": 0.982689, + "ave_all_frame_msssim_u": 0.988037, + "ave_all_frame_msssim_v": 0.990604, + "qp": 28, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.023976, + "ave_i_frame_psnr": 37.430623, + "ave_i_frame_msssim": 0.978687, + "ave_i_frame_psnr_y": 36.083907, + "ave_i_frame_psnr_u": 41.435282, + "ave_i_frame_psnr_v": 41.506261, + "ave_i_frame_msssim_y": 0.976137, + "ave_i_frame_msssim_u": 0.984999, + "ave_i_frame_msssim_v": 0.987676, + "test_time": 168887.813599, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.023976, + "ave_all_frame_psnr": 37.430623, + "ave_all_frame_msssim": 0.978687, + "ave_all_frame_psnr_y": 36.083907, + "ave_all_frame_psnr_u": 41.435282, + "ave_all_frame_psnr_v": 41.506261, + "ave_all_frame_msssim_y": 0.976137, + "ave_all_frame_msssim_u": 0.984999, + "ave_all_frame_msssim_v": 0.987676, + "qp": 31, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016151, + "ave_i_frame_psnr": 36.347209, + "ave_i_frame_msssim": 0.971688, + "ave_i_frame_psnr_y": 34.968140, + "ave_i_frame_psnr_u": 40.575672, + "ave_i_frame_psnr_v": 40.393158, + "ave_i_frame_msssim_y": 0.968133, + "ave_i_frame_msssim_u": 0.980929, + "ave_i_frame_msssim_v": 0.983780, + "test_time": 129710.941245, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016151, + "ave_all_frame_psnr": 36.347209, + "ave_all_frame_msssim": 0.971688, + "ave_all_frame_psnr_y": 34.968140, + "ave_all_frame_psnr_u": 40.575672, + "ave_all_frame_psnr_v": 40.393158, + "ave_all_frame_msssim_y": 0.968133, + "ave_all_frame_msssim_u": 0.980929, + "ave_all_frame_msssim_v": 0.983780, + "qp": 34, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.010895, + "ave_i_frame_psnr": 35.229597, + "ave_i_frame_msssim": 0.962664, + "ave_i_frame_psnr_y": 33.759488, + "ave_i_frame_psnr_u": 39.896525, + "ave_i_frame_psnr_v": 39.383318, + "ave_i_frame_msssim_y": 0.957259, + "ave_i_frame_msssim_u": 0.977702, + "ave_i_frame_msssim_v": 0.980059, + "test_time": 110961.344840, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.010895, + "ave_all_frame_psnr": 35.229597, + "ave_all_frame_msssim": 0.962664, + "ave_all_frame_psnr_y": 33.759488, + "ave_all_frame_psnr_u": 39.896525, + "ave_all_frame_psnr_v": 39.383318, + "ave_all_frame_msssim_y": 0.957259, + "ave_all_frame_msssim_u": 0.977702, + "ave_all_frame_msssim_v": 0.980059, + "qp": 37, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007237, + "ave_i_frame_psnr": 34.019510, + "ave_i_frame_msssim": 0.950231, + "ave_i_frame_psnr_y": 32.455138, + "ave_i_frame_psnr_u": 39.142030, + "ave_i_frame_psnr_v": 38.283221, + "ave_i_frame_msssim_y": 0.942332, + "ave_i_frame_msssim_u": 0.973131, + "ave_i_frame_msssim_v": 0.974724, + "test_time": 90868.039006, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007237, + "ave_all_frame_psnr": 34.019510, + "ave_all_frame_msssim": 0.950231, + "ave_all_frame_psnr_y": 32.455138, + "ave_all_frame_psnr_u": 39.142030, + "ave_all_frame_psnr_v": 38.283221, + "ave_all_frame_msssim_y": 0.942332, + "ave_all_frame_msssim_u": 0.973131, + "ave_all_frame_msssim_v": 0.974724, + "qp": 40, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004785, + "ave_i_frame_psnr": 32.757080, + "ave_i_frame_msssim": 0.934276, + "ave_i_frame_psnr_y": 31.100547, + "ave_i_frame_psnr_u": 38.305718, + "ave_i_frame_psnr_v": 37.147644, + "ave_i_frame_msssim_y": 0.923316, + "ave_i_frame_msssim_u": 0.966662, + "ave_i_frame_msssim_v": 0.967650, + "test_time": 69331.701732, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004785, + "ave_all_frame_psnr": 32.757080, + "ave_all_frame_msssim": 0.934276, + "ave_all_frame_psnr_y": 31.100547, + "ave_all_frame_psnr_u": 38.305718, + "ave_all_frame_psnr_v": 37.147644, + "ave_all_frame_msssim_y": 0.923316, + "ave_all_frame_msssim_u": 0.966662, + "ave_all_frame_msssim_v": 0.967650, + "qp": 43, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003125, + "ave_i_frame_psnr": 31.374815, + "ave_i_frame_msssim": 0.912077, + "ave_i_frame_psnr_y": 29.673807, + "ave_i_frame_psnr_u": 37.198585, + "ave_i_frame_psnr_v": 35.757095, + "ave_i_frame_msssim_y": 0.897363, + "ave_i_frame_msssim_u": 0.956490, + "ave_i_frame_msssim_v": 0.955943, + "test_time": 51787.508821, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003125, + "ave_all_frame_psnr": 31.374815, + "ave_all_frame_msssim": 0.912077, + "ave_all_frame_psnr_y": 29.673807, + "ave_all_frame_psnr_u": 37.198585, + "ave_all_frame_psnr_v": 35.757095, + "ave_all_frame_msssim_y": 0.897363, + "ave_all_frame_msssim_u": 0.956490, + "ave_all_frame_msssim_v": 0.955943, + "qp": 46, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002023, + "ave_i_frame_psnr": 29.939274, + "ave_i_frame_msssim": 0.884204, + "ave_i_frame_psnr_y": 28.211490, + "ave_i_frame_psnr_u": 35.995827, + "ave_i_frame_psnr_v": 34.249424, + "ave_i_frame_msssim_y": 0.865245, + "ave_i_frame_msssim_u": 0.943110, + "ave_i_frame_msssim_v": 0.939051, + "test_time": 38490.867930, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002023, + "ave_all_frame_psnr": 29.939274, + "ave_all_frame_msssim": 0.884204, + "ave_all_frame_psnr_y": 28.211490, + "ave_all_frame_psnr_u": 35.995827, + "ave_all_frame_psnr_v": 34.249424, + "ave_all_frame_msssim_y": 0.865245, + "ave_all_frame_msssim_u": 0.943110, + "ave_all_frame_msssim_v": 0.939051, + "qp": 49, + "ds_name": "HEVC_B", + "seq_name": "BasketballDrive_1920x1080_50.yuv" + } + }, + "Cactus_1920x1080_50.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.107342, + "ave_i_frame_psnr": 39.340006, + "ave_i_frame_msssim": 0.989854, + "ave_i_frame_psnr_y": 38.572573, + "ave_i_frame_psnr_u": 39.970201, + "ave_i_frame_psnr_v": 43.314410, + "ave_i_frame_msssim_y": 0.990269, + "ave_i_frame_msssim_u": 0.984681, + "ave_i_frame_msssim_v": 0.992531, + "test_time": 344890.592024, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.107342, + "ave_all_frame_psnr": 39.340006, + "ave_all_frame_msssim": 0.989854, + "ave_all_frame_psnr_y": 38.572573, + "ave_all_frame_psnr_u": 39.970201, + "ave_all_frame_psnr_v": 43.314410, + "ave_all_frame_msssim_y": 0.990269, + "ave_all_frame_msssim_u": 0.984681, + "ave_all_frame_msssim_v": 0.992531, + "qp": 22, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.049678, + "ave_i_frame_psnr": 38.340338, + "ave_i_frame_msssim": 0.986921, + "ave_i_frame_psnr_y": 37.494940, + "ave_i_frame_psnr_u": 39.446252, + "ave_i_frame_psnr_v": 42.306816, + "ave_i_frame_msssim_y": 0.987362, + "ave_i_frame_msssim_u": 0.981375, + "ave_i_frame_msssim_v": 0.989820, + "test_time": 220775.482064, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.049678, + "ave_all_frame_psnr": 38.340338, + "ave_all_frame_msssim": 0.986921, + "ave_all_frame_psnr_y": 37.494940, + "ave_all_frame_psnr_u": 39.446252, + "ave_all_frame_psnr_v": 42.306816, + "ave_all_frame_msssim_y": 0.987362, + "ave_all_frame_msssim_u": 0.981375, + "ave_all_frame_msssim_v": 0.989820, + "qp": 25, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.028787, + "ave_i_frame_psnr": 37.298711, + "ave_i_frame_msssim": 0.982726, + "ave_i_frame_psnr_y": 36.368384, + "ave_i_frame_psnr_u": 38.937754, + "ave_i_frame_psnr_v": 41.241629, + "ave_i_frame_msssim_y": 0.982998, + "ave_i_frame_msssim_u": 0.977670, + "ave_i_frame_msssim_v": 0.986156, + "test_time": 162081.470255, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.028787, + "ave_all_frame_psnr": 37.298711, + "ave_all_frame_msssim": 0.982726, + "ave_all_frame_psnr_y": 36.368384, + "ave_all_frame_psnr_u": 38.937754, + "ave_all_frame_psnr_v": 41.241629, + "ave_all_frame_msssim_y": 0.982998, + "ave_all_frame_msssim_u": 0.977670, + "ave_all_frame_msssim_v": 0.986156, + "qp": 28, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.017584, + "ave_i_frame_psnr": 36.161116, + "ave_i_frame_msssim": 0.976632, + "ave_i_frame_psnr_y": 35.109999, + "ave_i_frame_psnr_u": 38.399112, + "ave_i_frame_psnr_v": 40.229828, + "ave_i_frame_msssim_y": 0.976331, + "ave_i_frame_msssim_u": 0.973212, + "ave_i_frame_msssim_v": 0.981858, + "test_time": 128051.668201, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.017584, + "ave_all_frame_psnr": 36.161116, + "ave_all_frame_msssim": 0.976632, + "ave_all_frame_psnr_y": 35.109999, + "ave_all_frame_psnr_u": 38.399112, + "ave_all_frame_psnr_v": 40.229828, + "ave_all_frame_msssim_y": 0.976331, + "ave_all_frame_msssim_u": 0.973212, + "ave_all_frame_msssim_v": 0.981858, + "qp": 31, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.011568, + "ave_i_frame_psnr": 35.009877, + "ave_i_frame_msssim": 0.968378, + "ave_i_frame_psnr_y": 33.865588, + "ave_i_frame_psnr_u": 37.764355, + "ave_i_frame_psnr_v": 39.121128, + "ave_i_frame_msssim_y": 0.967313, + "ave_i_frame_msssim_u": 0.967222, + "ave_i_frame_msssim_v": 0.975919, + "test_time": 108083.284448, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.011568, + "ave_all_frame_psnr": 35.009877, + "ave_all_frame_msssim": 0.968378, + "ave_all_frame_psnr_y": 33.865588, + "ave_all_frame_psnr_u": 37.764355, + "ave_all_frame_psnr_v": 39.121128, + "ave_all_frame_msssim_y": 0.967313, + "ave_all_frame_msssim_u": 0.967222, + "ave_all_frame_msssim_v": 0.975919, + "qp": 34, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007612, + "ave_i_frame_psnr": 33.802251, + "ave_i_frame_msssim": 0.956755, + "ave_i_frame_psnr_y": 32.535993, + "ave_i_frame_psnr_u": 37.000190, + "ave_i_frame_psnr_v": 38.201857, + "ave_i_frame_msssim_y": 0.953852, + "ave_i_frame_msssim_u": 0.960012, + "ave_i_frame_msssim_v": 0.970916, + "test_time": 90403.432687, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007612, + "ave_all_frame_psnr": 33.802251, + "ave_all_frame_msssim": 0.956755, + "ave_all_frame_psnr_y": 32.535993, + "ave_all_frame_psnr_u": 37.000190, + "ave_all_frame_psnr_v": 38.201857, + "ave_all_frame_msssim_y": 0.953852, + "ave_all_frame_msssim_u": 0.960012, + "ave_all_frame_msssim_v": 0.970916, + "qp": 37, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004956, + "ave_i_frame_psnr": 32.596839, + "ave_i_frame_msssim": 0.941105, + "ave_i_frame_psnr_y": 31.183366, + "ave_i_frame_psnr_u": 36.382240, + "ave_i_frame_psnr_v": 37.292272, + "ave_i_frame_msssim_y": 0.935460, + "ave_i_frame_msssim_u": 0.952101, + "ave_i_frame_msssim_v": 0.963979, + "test_time": 70908.847060, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004956, + "ave_all_frame_psnr": 32.596839, + "ave_all_frame_msssim": 0.941105, + "ave_all_frame_psnr_y": 31.183366, + "ave_all_frame_psnr_u": 36.382240, + "ave_all_frame_psnr_v": 37.292272, + "ave_all_frame_msssim_y": 0.935460, + "ave_all_frame_msssim_u": 0.952101, + "ave_all_frame_msssim_v": 0.963979, + "qp": 40, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003221, + "ave_i_frame_psnr": 31.392601, + "ave_i_frame_msssim": 0.920884, + "ave_i_frame_psnr_y": 29.795968, + "ave_i_frame_psnr_u": 35.871253, + "ave_i_frame_psnr_v": 36.493749, + "ave_i_frame_msssim_y": 0.911041, + "ave_i_frame_msssim_u": 0.944612, + "ave_i_frame_msssim_v": 0.956210, + "test_time": 54457.272378, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003221, + "ave_all_frame_psnr": 31.392601, + "ave_all_frame_msssim": 0.920884, + "ave_all_frame_psnr_y": 29.795968, + "ave_all_frame_psnr_u": 35.871253, + "ave_all_frame_psnr_v": 36.493749, + "ave_all_frame_msssim_y": 0.911041, + "ave_all_frame_msssim_u": 0.944612, + "ave_all_frame_msssim_v": 0.956210, + "qp": 43, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002065, + "ave_i_frame_psnr": 30.050242, + "ave_i_frame_msssim": 0.893554, + "ave_i_frame_psnr_y": 28.364430, + "ave_i_frame_psnr_u": 35.020549, + "ave_i_frame_psnr_v": 35.194811, + "ave_i_frame_msssim_y": 0.879233, + "ave_i_frame_msssim_u": 0.931428, + "ave_i_frame_msssim_v": 0.941604, + "test_time": 41664.537653, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002065, + "ave_all_frame_psnr": 30.050242, + "ave_all_frame_msssim": 0.893554, + "ave_all_frame_psnr_y": 28.364430, + "ave_all_frame_psnr_u": 35.020549, + "ave_all_frame_psnr_v": 35.194811, + "ave_all_frame_msssim_y": 0.879233, + "ave_all_frame_msssim_u": 0.931428, + "ave_all_frame_msssim_v": 0.941604, + "qp": 46, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001329, + "ave_i_frame_psnr": 28.676159, + "ave_i_frame_msssim": 0.856625, + "ave_i_frame_psnr_y": 26.918576, + "ave_i_frame_psnr_u": 34.063936, + "ave_i_frame_psnr_v": 33.833879, + "ave_i_frame_msssim_y": 0.836243, + "ave_i_frame_msssim_u": 0.913822, + "ave_i_frame_msssim_v": 0.921716, + "test_time": 32481.527578, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001329, + "ave_all_frame_psnr": 28.676159, + "ave_all_frame_msssim": 0.856625, + "ave_all_frame_psnr_y": 26.918576, + "ave_all_frame_psnr_u": 34.063936, + "ave_all_frame_psnr_v": 33.833879, + "ave_all_frame_msssim_y": 0.836243, + "ave_all_frame_msssim_u": 0.913822, + "ave_all_frame_msssim_v": 0.921716, + "qp": 49, + "ds_name": "HEVC_B", + "seq_name": "Cactus_1920x1080_50.yuv" + } + }, + "Kimono1_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.078177, + "ave_i_frame_psnr": 42.331098, + "ave_i_frame_msssim": 0.991768, + "ave_i_frame_psnr_y": 41.713020, + "ave_i_frame_psnr_u": 43.275274, + "ave_i_frame_psnr_v": 45.095396, + "ave_i_frame_msssim_y": 0.992453, + "ave_i_frame_msssim_u": 0.988245, + "ave_i_frame_msssim_v": 0.991177, + "test_time": 157158.116172, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.078177, + "ave_all_frame_psnr": 42.331098, + "ave_all_frame_msssim": 0.991768, + "ave_all_frame_psnr_y": 41.713020, + "ave_all_frame_psnr_u": 43.275274, + "ave_all_frame_psnr_v": 45.095396, + "ave_all_frame_msssim_y": 0.992453, + "ave_all_frame_msssim_u": 0.988245, + "ave_all_frame_msssim_v": 0.991177, + "qp": 22, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.048485, + "ave_i_frame_psnr": 41.220754, + "ave_i_frame_msssim": 0.988544, + "ave_i_frame_psnr_y": 40.566123, + "ave_i_frame_psnr_u": 42.328724, + "ave_i_frame_psnr_v": 44.040573, + "ave_i_frame_msssim_y": 0.989426, + "ave_i_frame_msssim_u": 0.983937, + "ave_i_frame_msssim_v": 0.987863, + "test_time": 122287.951528, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.048485, + "ave_all_frame_psnr": 41.220754, + "ave_all_frame_msssim": 0.988544, + "ave_all_frame_psnr_y": 40.566123, + "ave_all_frame_psnr_u": 42.328724, + "ave_all_frame_psnr_v": 44.040573, + "ave_all_frame_msssim_y": 0.989426, + "ave_all_frame_msssim_u": 0.983937, + "ave_all_frame_msssim_v": 0.987863, + "qp": 25, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.030357, + "ave_i_frame_psnr": 39.902500, + "ave_i_frame_msssim": 0.983397, + "ave_i_frame_psnr_y": 39.126911, + "ave_i_frame_psnr_u": 41.408681, + "ave_i_frame_psnr_v": 43.049854, + "ave_i_frame_msssim_y": 0.984096, + "ave_i_frame_msssim_u": 0.978618, + "ave_i_frame_msssim_v": 0.983982, + "test_time": 102893.929726, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.030357, + "ave_all_frame_psnr": 39.902500, + "ave_all_frame_msssim": 0.983397, + "ave_all_frame_psnr_y": 39.126911, + "ave_all_frame_psnr_u": 41.408681, + "ave_all_frame_psnr_v": 43.049854, + "ave_all_frame_msssim_y": 0.984096, + "ave_all_frame_msssim_u": 0.978618, + "ave_all_frame_msssim_v": 0.983982, + "qp": 28, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.019047, + "ave_i_frame_psnr": 38.467328, + "ave_i_frame_msssim": 0.975642, + "ave_i_frame_psnr_y": 37.478533, + "ave_i_frame_psnr_u": 40.642648, + "ave_i_frame_psnr_v": 42.224776, + "ave_i_frame_msssim_y": 0.975260, + "ave_i_frame_msssim_u": 0.973321, + "ave_i_frame_msssim_v": 0.980253, + "test_time": 81065.107711, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.019047, + "ave_all_frame_psnr": 38.467328, + "ave_all_frame_msssim": 0.975642, + "ave_all_frame_psnr_y": 37.478533, + "ave_all_frame_psnr_u": 40.642648, + "ave_all_frame_psnr_v": 42.224776, + "ave_all_frame_msssim_y": 0.975260, + "ave_all_frame_msssim_u": 0.973321, + "ave_all_frame_msssim_v": 0.980253, + "qp": 31, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.012643, + "ave_i_frame_psnr": 37.159446, + "ave_i_frame_msssim": 0.965771, + "ave_i_frame_psnr_y": 35.999810, + "ave_i_frame_psnr_u": 39.833914, + "ave_i_frame_psnr_v": 41.442797, + "ave_i_frame_msssim_y": 0.963943, + "ave_i_frame_msssim_u": 0.966451, + "ave_i_frame_msssim_v": 0.976064, + "test_time": 61996.893653, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.012643, + "ave_all_frame_psnr": 37.159446, + "ave_all_frame_msssim": 0.965771, + "ave_all_frame_psnr_y": 35.999810, + "ave_all_frame_psnr_u": 39.833914, + "ave_all_frame_psnr_v": 41.442797, + "ave_all_frame_msssim_y": 0.963943, + "ave_all_frame_msssim_u": 0.966451, + "ave_all_frame_msssim_v": 0.976064, + "qp": 34, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008270, + "ave_i_frame_psnr": 35.795823, + "ave_i_frame_msssim": 0.951971, + "ave_i_frame_psnr_y": 34.464165, + "ave_i_frame_psnr_u": 39.178918, + "ave_i_frame_psnr_v": 40.402674, + "ave_i_frame_msssim_y": 0.947638, + "ave_i_frame_msssim_u": 0.960366, + "ave_i_frame_msssim_v": 0.969577, + "test_time": 47074.912929, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008270, + "ave_all_frame_psnr": 35.795823, + "ave_all_frame_msssim": 0.951971, + "ave_all_frame_psnr_y": 34.464165, + "ave_all_frame_psnr_u": 39.178918, + "ave_all_frame_psnr_v": 40.402674, + "ave_all_frame_msssim_y": 0.947638, + "ave_all_frame_msssim_u": 0.960366, + "ave_all_frame_msssim_v": 0.969577, + "qp": 37, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005306, + "ave_i_frame_psnr": 34.527352, + "ave_i_frame_msssim": 0.934223, + "ave_i_frame_psnr_y": 32.947686, + "ave_i_frame_psnr_u": 38.543988, + "ave_i_frame_psnr_v": 39.988712, + "ave_i_frame_msssim_y": 0.925702, + "ave_i_frame_msssim_u": 0.953211, + "ave_i_frame_msssim_v": 0.966363, + "test_time": 34941.357389, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005306, + "ave_all_frame_psnr": 34.527352, + "ave_all_frame_msssim": 0.934223, + "ave_all_frame_psnr_y": 32.947686, + "ave_all_frame_psnr_u": 38.543988, + "ave_all_frame_psnr_v": 39.988712, + "ave_all_frame_msssim_y": 0.925702, + "ave_all_frame_msssim_u": 0.953211, + "ave_all_frame_msssim_v": 0.966363, + "qp": 40, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003345, + "ave_i_frame_psnr": 33.288460, + "ave_i_frame_msssim": 0.911780, + "ave_i_frame_psnr_y": 31.464566, + "ave_i_frame_psnr_u": 37.978162, + "ave_i_frame_psnr_v": 39.542118, + "ave_i_frame_msssim_y": 0.897516, + "ave_i_frame_msssim_u": 0.946435, + "ave_i_frame_msssim_v": 0.962714, + "test_time": 26258.423957, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003345, + "ave_all_frame_psnr": 33.288460, + "ave_all_frame_msssim": 0.911780, + "ave_all_frame_psnr_y": 31.464566, + "ave_all_frame_psnr_u": 37.978162, + "ave_all_frame_psnr_v": 39.542118, + "ave_all_frame_msssim_y": 0.897516, + "ave_all_frame_msssim_u": 0.946435, + "ave_all_frame_msssim_v": 0.962714, + "qp": 43, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002068, + "ave_i_frame_psnr": 32.039458, + "ave_i_frame_msssim": 0.883632, + "ave_i_frame_psnr_y": 30.050988, + "ave_i_frame_psnr_u": 37.180076, + "ave_i_frame_psnr_v": 38.829662, + "ave_i_frame_msssim_y": 0.862601, + "ave_i_frame_msssim_u": 0.936176, + "ave_i_frame_msssim_v": 0.957275, + "test_time": 19468.246550, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002068, + "ave_all_frame_psnr": 32.039458, + "ave_all_frame_msssim": 0.883632, + "ave_all_frame_psnr_y": 30.050988, + "ave_all_frame_psnr_u": 37.180076, + "ave_all_frame_psnr_v": 38.829662, + "ave_all_frame_msssim_y": 0.862601, + "ave_all_frame_msssim_u": 0.936176, + "ave_all_frame_msssim_v": 0.957275, + "qp": 46, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001249, + "ave_i_frame_psnr": 30.851346, + "ave_i_frame_msssim": 0.851428, + "ave_i_frame_psnr_y": 28.724813, + "ave_i_frame_psnr_u": 36.296465, + "ave_i_frame_psnr_v": 38.165424, + "ave_i_frame_msssim_y": 0.822595, + "ave_i_frame_msssim_u": 0.923796, + "ave_i_frame_msssim_v": 0.952059, + "test_time": 14069.280591, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001249, + "ave_all_frame_psnr": 30.851346, + "ave_all_frame_msssim": 0.851428, + "ave_all_frame_psnr_y": 28.724813, + "ave_all_frame_psnr_u": 36.296465, + "ave_all_frame_psnr_v": 38.165424, + "ave_all_frame_msssim_y": 0.822595, + "ave_all_frame_msssim_u": 0.923796, + "ave_all_frame_msssim_v": 0.952059, + "qp": 49, + "ds_name": "HEVC_B", + "seq_name": "Kimono1_1920x1080_24.yuv" + } + }, + "ParkScene_1920x1080_24.yuv": { + "022": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.118100, + "ave_i_frame_psnr": 40.469166, + "ave_i_frame_msssim": 0.990954, + "ave_i_frame_psnr_y": 39.747635, + "ave_i_frame_psnr_u": 41.746605, + "ave_i_frame_psnr_v": 43.520913, + "ave_i_frame_msssim_y": 0.991663, + "ave_i_frame_msssim_u": 0.987830, + "ave_i_frame_msssim_v": 0.989829, + "test_time": 134865.136006, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.118100, + "ave_all_frame_psnr": 40.469166, + "ave_all_frame_msssim": 0.990954, + "ave_all_frame_psnr_y": 39.747635, + "ave_all_frame_psnr_u": 41.746605, + "ave_all_frame_psnr_v": 43.520913, + "ave_all_frame_msssim_y": 0.991663, + "ave_all_frame_msssim_u": 0.987830, + "ave_all_frame_msssim_v": 0.989829, + "qp": 22, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "025": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.066291, + "ave_i_frame_psnr": 38.857342, + "ave_i_frame_msssim": 0.986589, + "ave_i_frame_psnr_y": 37.984546, + "ave_i_frame_psnr_u": 40.566507, + "ave_i_frame_psnr_v": 42.384955, + "ave_i_frame_msssim_y": 0.987337, + "ave_i_frame_msssim_u": 0.983155, + "ave_i_frame_msssim_v": 0.985536, + "test_time": 112428.263097, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.066291, + "ave_all_frame_psnr": 38.857342, + "ave_all_frame_msssim": 0.986589, + "ave_all_frame_psnr_y": 37.984546, + "ave_all_frame_psnr_u": 40.566507, + "ave_all_frame_psnr_v": 42.384955, + "ave_all_frame_msssim_y": 0.987337, + "ave_all_frame_msssim_u": 0.983155, + "ave_all_frame_msssim_v": 0.985536, + "qp": 25, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "028": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.038231, + "ave_i_frame_psnr": 37.290791, + "ave_i_frame_msssim": 0.980186, + "ave_i_frame_psnr_y": 36.249273, + "ave_i_frame_psnr_u": 39.451255, + "ave_i_frame_psnr_v": 41.379431, + "ave_i_frame_msssim_y": 0.980674, + "ave_i_frame_msssim_u": 0.976887, + "ave_i_frame_msssim_v": 0.980554, + "test_time": 90655.809546, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.038231, + "ave_all_frame_psnr": 37.290791, + "ave_all_frame_msssim": 0.980186, + "ave_all_frame_psnr_y": 36.249273, + "ave_all_frame_psnr_u": 39.451255, + "ave_all_frame_psnr_v": 41.379431, + "ave_all_frame_msssim_y": 0.980674, + "ave_all_frame_msssim_u": 0.976887, + "ave_all_frame_msssim_v": 0.980554, + "qp": 28, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "031": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022358, + "ave_i_frame_psnr": 35.812038, + "ave_i_frame_msssim": 0.971210, + "ave_i_frame_psnr_y": 34.581247, + "ave_i_frame_psnr_u": 38.454921, + "ave_i_frame_psnr_v": 40.553907, + "ave_i_frame_msssim_y": 0.970846, + "ave_i_frame_msssim_u": 0.969131, + "ave_i_frame_msssim_v": 0.975476, + "test_time": 69109.798470, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022358, + "ave_all_frame_psnr": 35.812038, + "ave_all_frame_msssim": 0.971210, + "ave_all_frame_psnr_y": 34.581247, + "ave_all_frame_psnr_u": 38.454921, + "ave_all_frame_psnr_v": 40.553907, + "ave_all_frame_msssim_y": 0.970846, + "ave_all_frame_msssim_u": 0.969131, + "ave_all_frame_msssim_v": 0.975476, + "qp": 31, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "034": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013772, + "ave_i_frame_psnr": 34.482363, + "ave_i_frame_msssim": 0.959329, + "ave_i_frame_psnr_y": 33.098852, + "ave_i_frame_psnr_u": 37.492985, + "ave_i_frame_psnr_v": 39.772802, + "ave_i_frame_msssim_y": 0.957631, + "ave_i_frame_msssim_u": 0.958984, + "ave_i_frame_msssim_v": 0.969862, + "test_time": 53240.093564, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013772, + "ave_all_frame_psnr": 34.482363, + "ave_all_frame_msssim": 0.959329, + "ave_all_frame_psnr_y": 33.098852, + "ave_all_frame_psnr_u": 37.492985, + "ave_all_frame_psnr_v": 39.772802, + "ave_all_frame_msssim_y": 0.957631, + "ave_all_frame_msssim_u": 0.958984, + "ave_all_frame_msssim_v": 0.969862, + "qp": 34, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "037": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008372, + "ave_i_frame_psnr": 33.141898, + "ave_i_frame_msssim": 0.943084, + "ave_i_frame_psnr_y": 31.642312, + "ave_i_frame_psnr_u": 36.834375, + "ave_i_frame_psnr_v": 38.446935, + "ave_i_frame_msssim_y": 0.938501, + "ave_i_frame_msssim_u": 0.952038, + "ave_i_frame_msssim_v": 0.961629, + "test_time": 41343.586527, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008372, + "ave_all_frame_psnr": 33.141898, + "ave_all_frame_msssim": 0.943084, + "ave_all_frame_psnr_y": 31.642312, + "ave_all_frame_psnr_u": 36.834375, + "ave_all_frame_psnr_v": 38.446935, + "ave_all_frame_msssim_y": 0.938501, + "ave_all_frame_msssim_u": 0.952038, + "ave_all_frame_msssim_v": 0.961629, + "qp": 37, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "040": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005020, + "ave_i_frame_psnr": 31.981517, + "ave_i_frame_msssim": 0.921714, + "ave_i_frame_psnr_y": 30.259064, + "ave_i_frame_psnr_u": 36.240430, + "ave_i_frame_psnr_v": 38.057319, + "ave_i_frame_msssim_y": 0.912235, + "ave_i_frame_msssim_u": 0.942711, + "ave_i_frame_msssim_v": 0.957591, + "test_time": 32012.827418, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005020, + "ave_all_frame_psnr": 31.981517, + "ave_all_frame_msssim": 0.921714, + "ave_all_frame_psnr_y": 30.259064, + "ave_all_frame_psnr_u": 36.240430, + "ave_all_frame_psnr_v": 38.057319, + "ave_all_frame_msssim_y": 0.912235, + "ave_all_frame_msssim_u": 0.942711, + "ave_all_frame_msssim_v": 0.957591, + "qp": 40, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "043": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002958, + "ave_i_frame_psnr": 30.889225, + "ave_i_frame_msssim": 0.893853, + "ave_i_frame_psnr_y": 28.938423, + "ave_i_frame_psnr_u": 35.710159, + "ave_i_frame_psnr_v": 37.773102, + "ave_i_frame_msssim_y": 0.877240, + "ave_i_frame_msssim_u": 0.933398, + "ave_i_frame_msssim_v": 0.953986, + "test_time": 25433.944611, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002958, + "ave_all_frame_psnr": 30.889225, + "ave_all_frame_msssim": 0.893853, + "ave_all_frame_psnr_y": 28.938423, + "ave_all_frame_psnr_u": 35.710159, + "ave_all_frame_psnr_v": 37.773102, + "ave_all_frame_msssim_y": 0.877240, + "ave_all_frame_msssim_u": 0.933398, + "ave_all_frame_msssim_v": 0.953986, + "qp": 43, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "046": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001715, + "ave_i_frame_psnr": 29.813171, + "ave_i_frame_msssim": 0.857921, + "ave_i_frame_psnr_y": 27.706036, + "ave_i_frame_psnr_u": 35.020480, + "ave_i_frame_psnr_v": 37.248671, + "ave_i_frame_msssim_y": 0.832864, + "ave_i_frame_msssim_u": 0.918774, + "ave_i_frame_msssim_v": 0.947409, + "test_time": 19274.153854, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001715, + "ave_all_frame_psnr": 29.813171, + "ave_all_frame_msssim": 0.857921, + "ave_all_frame_psnr_y": 27.706036, + "ave_all_frame_psnr_u": 35.020480, + "ave_all_frame_psnr_v": 37.248671, + "ave_all_frame_msssim_y": 0.832864, + "ave_all_frame_msssim_u": 0.918774, + "ave_all_frame_msssim_v": 0.947409, + "qp": 46, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + }, + "049": { + "frame_pixel_num": 2073600, + "i_frame_num": 240, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001005, + "ave_i_frame_psnr": 28.817181, + "ave_i_frame_msssim": 0.817773, + "ave_i_frame_psnr_y": 26.590940, + "ave_i_frame_psnr_u": 34.260478, + "ave_i_frame_psnr_v": 36.731330, + "ave_i_frame_msssim_y": 0.783462, + "ave_i_frame_msssim_u": 0.900985, + "ave_i_frame_msssim_v": 0.940427, + "test_time": 14370.919342, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001005, + "ave_all_frame_psnr": 28.817181, + "ave_all_frame_msssim": 0.817773, + "ave_all_frame_psnr_y": 26.590940, + "ave_all_frame_psnr_u": 34.260478, + "ave_all_frame_psnr_v": 36.731330, + "ave_all_frame_msssim_y": 0.783462, + "ave_all_frame_msssim_u": 0.900985, + "ave_all_frame_msssim_v": 0.940427, + "qp": 49, + "ds_name": "HEVC_B", + "seq_name": "ParkScene_1920x1080_24.yuv" + } + } + }, + "HEVC_E": { + "FourPeople_1280x720_60.yuv": { + "022": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.026730, + "ave_i_frame_psnr": 43.797679, + "ave_i_frame_msssim": 0.995433, + "ave_i_frame_psnr_y": 42.696640, + "ave_i_frame_psnr_u": 46.491752, + "ave_i_frame_psnr_v": 47.709840, + "ave_i_frame_msssim_y": 0.995547, + "ave_i_frame_msssim_u": 0.994441, + "ave_i_frame_msssim_v": 0.995747, + "test_time": 76399.278210, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.026730, + "ave_all_frame_psnr": 43.797679, + "ave_all_frame_msssim": 0.995433, + "ave_all_frame_psnr_y": 42.696640, + "ave_all_frame_psnr_u": 46.491752, + "ave_all_frame_psnr_v": 47.709840, + "ave_all_frame_msssim_y": 0.995547, + "ave_all_frame_msssim_u": 0.994441, + "ave_all_frame_msssim_v": 0.995747, + "qp": 22, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "025": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014927, + "ave_i_frame_psnr": 42.615446, + "ave_i_frame_msssim": 0.994200, + "ave_i_frame_psnr_y": 41.435897, + "ave_i_frame_psnr_u": 45.603935, + "ave_i_frame_psnr_v": 46.704251, + "ave_i_frame_msssim_y": 0.994428, + "ave_i_frame_msssim_u": 0.992759, + "ave_i_frame_msssim_v": 0.994272, + "test_time": 59579.643680, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014927, + "ave_all_frame_psnr": 42.615446, + "ave_all_frame_msssim": 0.994200, + "ave_all_frame_psnr_y": 41.435897, + "ave_all_frame_psnr_u": 45.603935, + "ave_all_frame_psnr_v": 46.704251, + "ave_all_frame_msssim_y": 0.994428, + "ave_all_frame_msssim_u": 0.992759, + "ave_all_frame_msssim_v": 0.994272, + "qp": 25, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "028": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009339, + "ave_i_frame_psnr": 41.322970, + "ave_i_frame_msssim": 0.992365, + "ave_i_frame_psnr_y": 40.065312, + "ave_i_frame_psnr_u": 44.612460, + "ave_i_frame_psnr_v": 45.579427, + "ave_i_frame_msssim_y": 0.992736, + "ave_i_frame_msssim_u": 0.990373, + "ave_i_frame_msssim_v": 0.992131, + "test_time": 45279.861127, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009339, + "ave_all_frame_psnr": 41.322970, + "ave_all_frame_msssim": 0.992365, + "ave_all_frame_psnr_y": 40.065312, + "ave_all_frame_psnr_u": 44.612460, + "ave_all_frame_psnr_v": 45.579427, + "ave_all_frame_msssim_y": 0.992736, + "ave_all_frame_msssim_u": 0.990373, + "ave_all_frame_msssim_v": 0.992131, + "qp": 28, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "031": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006109, + "ave_i_frame_psnr": 39.888841, + "ave_i_frame_msssim": 0.989609, + "ave_i_frame_psnr_y": 38.538427, + "ave_i_frame_psnr_u": 43.496163, + "ave_i_frame_psnr_v": 44.384006, + "ave_i_frame_msssim_y": 0.990154, + "ave_i_frame_msssim_u": 0.986932, + "ave_i_frame_msssim_v": 0.989016, + "test_time": 35436.041821, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006109, + "ave_all_frame_psnr": 39.888841, + "ave_all_frame_msssim": 0.989609, + "ave_all_frame_psnr_y": 38.538427, + "ave_all_frame_psnr_u": 43.496163, + "ave_all_frame_psnr_v": 44.384006, + "ave_all_frame_msssim_y": 0.990154, + "ave_all_frame_msssim_u": 0.986932, + "ave_all_frame_msssim_v": 0.989016, + "qp": 31, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "034": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004215, + "ave_i_frame_psnr": 38.427862, + "ave_i_frame_msssim": 0.985696, + "ave_i_frame_psnr_y": 36.976272, + "ave_i_frame_psnr_u": 42.422419, + "ave_i_frame_psnr_v": 43.142847, + "ave_i_frame_msssim_y": 0.986384, + "ave_i_frame_msssim_u": 0.982528, + "ave_i_frame_msssim_v": 0.984732, + "test_time": 29008.829978, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004215, + "ave_all_frame_psnr": 38.427862, + "ave_all_frame_msssim": 0.985696, + "ave_all_frame_psnr_y": 36.976272, + "ave_all_frame_psnr_u": 42.422419, + "ave_all_frame_psnr_v": 43.142847, + "ave_all_frame_msssim_y": 0.986384, + "ave_all_frame_msssim_u": 0.982528, + "ave_all_frame_msssim_v": 0.984732, + "qp": 34, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "037": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002934, + "ave_i_frame_psnr": 36.920541, + "ave_i_frame_msssim": 0.980194, + "ave_i_frame_psnr_y": 35.287365, + "ave_i_frame_psnr_u": 41.242294, + "ave_i_frame_psnr_v": 42.397842, + "ave_i_frame_msssim_y": 0.980442, + "ave_i_frame_msssim_u": 0.977107, + "ave_i_frame_msssim_v": 0.981791, + "test_time": 23819.080202, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002934, + "ave_all_frame_psnr": 36.920541, + "ave_all_frame_msssim": 0.980194, + "ave_all_frame_psnr_y": 35.287365, + "ave_all_frame_psnr_u": 41.242294, + "ave_all_frame_psnr_v": 42.397842, + "ave_all_frame_msssim_y": 0.980442, + "ave_all_frame_msssim_u": 0.977107, + "ave_all_frame_msssim_v": 0.981791, + "qp": 37, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "040": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002020, + "ave_i_frame_psnr": 35.380431, + "ave_i_frame_msssim": 0.971980, + "ave_i_frame_psnr_y": 33.521149, + "ave_i_frame_psnr_u": 40.493620, + "ave_i_frame_psnr_v": 41.422935, + "ave_i_frame_msssim_y": 0.971104, + "ave_i_frame_msssim_u": 0.972271, + "ave_i_frame_msssim_v": 0.976946, + "test_time": 19539.853987, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002020, + "ave_all_frame_psnr": 35.380431, + "ave_all_frame_msssim": 0.971980, + "ave_all_frame_psnr_y": 33.521149, + "ave_all_frame_psnr_u": 40.493620, + "ave_all_frame_psnr_v": 41.422935, + "ave_all_frame_msssim_y": 0.971104, + "ave_all_frame_msssim_u": 0.972271, + "ave_all_frame_msssim_v": 0.976946, + "qp": 40, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "043": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001395, + "ave_i_frame_psnr": 33.853490, + "ave_i_frame_msssim": 0.960282, + "ave_i_frame_psnr_y": 31.679177, + "ave_i_frame_psnr_u": 39.922081, + "ave_i_frame_psnr_v": 40.830775, + "ave_i_frame_msssim_y": 0.956862, + "ave_i_frame_msssim_u": 0.967800, + "ave_i_frame_msssim_v": 0.973286, + "test_time": 16030.312824, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001395, + "ave_all_frame_psnr": 33.853490, + "ave_all_frame_msssim": 0.960282, + "ave_all_frame_psnr_y": 31.679177, + "ave_all_frame_psnr_u": 39.922081, + "ave_all_frame_psnr_v": 40.830775, + "ave_all_frame_msssim_y": 0.956862, + "ave_all_frame_msssim_u": 0.967800, + "ave_all_frame_msssim_v": 0.973286, + "qp": 43, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "046": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000951, + "ave_i_frame_psnr": 32.162572, + "ave_i_frame_msssim": 0.941906, + "ave_i_frame_psnr_y": 29.885002, + "ave_i_frame_psnr_u": 38.509061, + "ave_i_frame_psnr_v": 39.481500, + "ave_i_frame_msssim_y": 0.936252, + "ave_i_frame_msssim_u": 0.954789, + "ave_i_frame_msssim_v": 0.962943, + "test_time": 13551.872015, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000951, + "ave_all_frame_psnr": 32.162572, + "ave_all_frame_msssim": 0.941906, + "ave_all_frame_psnr_y": 29.885002, + "ave_all_frame_psnr_u": 38.509061, + "ave_all_frame_psnr_v": 39.481500, + "ave_all_frame_msssim_y": 0.936252, + "ave_all_frame_msssim_u": 0.954789, + "ave_all_frame_msssim_v": 0.962943, + "qp": 46, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + }, + "049": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000650, + "ave_i_frame_psnr": 30.442438, + "ave_i_frame_msssim": 0.916546, + "ave_i_frame_psnr_y": 28.102072, + "ave_i_frame_psnr_u": 37.036472, + "ave_i_frame_psnr_v": 37.890600, + "ave_i_frame_msssim_y": 0.907817, + "ave_i_frame_msssim_u": 0.937134, + "ave_i_frame_msssim_v": 0.948334, + "test_time": 11419.368901, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000650, + "ave_all_frame_psnr": 30.442438, + "ave_all_frame_msssim": 0.916546, + "ave_all_frame_psnr_y": 28.102072, + "ave_all_frame_psnr_u": 37.036472, + "ave_all_frame_psnr_v": 37.890600, + "ave_all_frame_msssim_y": 0.907817, + "ave_all_frame_msssim_u": 0.937134, + "ave_all_frame_msssim_v": 0.948334, + "qp": 49, + "ds_name": "HEVC_E", + "seq_name": "FourPeople_1280x720_60.yuv" + } + }, + "Johnny_1280x720_60.yuv": { + "022": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016448, + "ave_i_frame_psnr": 44.321094, + "ave_i_frame_msssim": 0.994640, + "ave_i_frame_psnr_y": 43.019713, + "ave_i_frame_psnr_u": 48.010644, + "ave_i_frame_psnr_v": 48.439830, + "ave_i_frame_msssim_y": 0.993979, + "ave_i_frame_msssim_u": 0.996417, + "ave_i_frame_msssim_v": 0.996831, + "test_time": 66694.938506, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016448, + "ave_all_frame_psnr": 44.321094, + "ave_all_frame_msssim": 0.994640, + "ave_all_frame_psnr_y": 43.019713, + "ave_all_frame_psnr_u": 48.010644, + "ave_all_frame_psnr_v": 48.439830, + "ave_all_frame_msssim_y": 0.993979, + "ave_all_frame_msssim_u": 0.996417, + "ave_all_frame_msssim_v": 0.996831, + "qp": 22, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "025": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007539, + "ave_i_frame_psnr": 43.470937, + "ave_i_frame_msssim": 0.993677, + "ave_i_frame_psnr_y": 42.133819, + "ave_i_frame_psnr_u": 47.311322, + "ave_i_frame_psnr_v": 47.653263, + "ave_i_frame_msssim_y": 0.992915, + "ave_i_frame_msssim_u": 0.995743, + "ave_i_frame_msssim_v": 0.996184, + "test_time": 47269.208689, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007539, + "ave_all_frame_psnr": 43.470937, + "ave_all_frame_msssim": 0.993677, + "ave_all_frame_psnr_y": 42.133819, + "ave_all_frame_psnr_u": 47.311322, + "ave_all_frame_psnr_v": 47.653263, + "ave_all_frame_msssim_y": 0.992915, + "ave_all_frame_msssim_u": 0.995743, + "ave_all_frame_msssim_v": 0.996184, + "qp": 25, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "028": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004217, + "ave_i_frame_psnr": 42.496630, + "ave_i_frame_msssim": 0.992286, + "ave_i_frame_psnr_y": 41.122174, + "ave_i_frame_psnr_u": 46.532694, + "ave_i_frame_psnr_v": 46.707305, + "ave_i_frame_msssim_y": 0.991384, + "ave_i_frame_msssim_u": 0.994765, + "ave_i_frame_msssim_v": 0.995214, + "test_time": 34317.642217, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004217, + "ave_all_frame_psnr": 42.496630, + "ave_all_frame_msssim": 0.992286, + "ave_all_frame_psnr_y": 41.122174, + "ave_all_frame_psnr_u": 46.532694, + "ave_all_frame_psnr_v": 46.707305, + "ave_all_frame_msssim_y": 0.991384, + "ave_all_frame_msssim_u": 0.994765, + "ave_all_frame_msssim_v": 0.995214, + "qp": 28, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "031": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002663, + "ave_i_frame_psnr": 41.388833, + "ave_i_frame_msssim": 0.990395, + "ave_i_frame_psnr_y": 39.989776, + "ave_i_frame_psnr_u": 45.496655, + "ave_i_frame_psnr_v": 45.675351, + "ave_i_frame_msssim_y": 0.989369, + "ave_i_frame_msssim_u": 0.993134, + "ave_i_frame_msssim_v": 0.993813, + "test_time": 26062.218753, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002663, + "ave_all_frame_psnr": 41.388833, + "ave_all_frame_msssim": 0.990395, + "ave_all_frame_psnr_y": 39.989776, + "ave_all_frame_psnr_u": 45.496655, + "ave_all_frame_psnr_v": 45.675351, + "ave_all_frame_msssim_y": 0.989369, + "ave_all_frame_msssim_u": 0.993134, + "ave_all_frame_msssim_v": 0.993813, + "qp": 31, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "034": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001831, + "ave_i_frame_psnr": 40.176620, + "ave_i_frame_msssim": 0.987589, + "ave_i_frame_psnr_y": 38.740611, + "ave_i_frame_psnr_u": 44.422089, + "ave_i_frame_psnr_v": 44.547207, + "ave_i_frame_msssim_y": 0.986332, + "ave_i_frame_msssim_u": 0.991067, + "ave_i_frame_msssim_v": 0.991655, + "test_time": 20515.191412, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001831, + "ave_all_frame_psnr": 40.176620, + "ave_all_frame_msssim": 0.987589, + "ave_all_frame_psnr_y": 38.740611, + "ave_all_frame_psnr_u": 44.422089, + "ave_all_frame_psnr_v": 44.547207, + "ave_all_frame_msssim_y": 0.986332, + "ave_all_frame_msssim_u": 0.991067, + "ave_all_frame_msssim_v": 0.991655, + "qp": 34, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "037": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001294, + "ave_i_frame_psnr": 38.909993, + "ave_i_frame_msssim": 0.983651, + "ave_i_frame_psnr_y": 37.385887, + "ave_i_frame_psnr_u": 43.129528, + "ave_i_frame_psnr_v": 43.835095, + "ave_i_frame_msssim_y": 0.982054, + "ave_i_frame_msssim_u": 0.986989, + "ave_i_frame_msssim_v": 0.989891, + "test_time": 16266.093946, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001294, + "ave_all_frame_psnr": 38.909993, + "ave_all_frame_msssim": 0.983651, + "ave_all_frame_psnr_y": 37.385887, + "ave_all_frame_psnr_u": 43.129528, + "ave_all_frame_psnr_v": 43.835095, + "ave_all_frame_msssim_y": 0.982054, + "ave_all_frame_msssim_u": 0.986989, + "ave_all_frame_msssim_v": 0.989891, + "qp": 37, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "040": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000930, + "ave_i_frame_psnr": 37.586121, + "ave_i_frame_msssim": 0.978344, + "ave_i_frame_psnr_y": 35.913034, + "ave_i_frame_psnr_u": 42.351289, + "ave_i_frame_psnr_v": 42.859472, + "ave_i_frame_msssim_y": 0.975832, + "ave_i_frame_msssim_u": 0.984428, + "ave_i_frame_msssim_v": 0.987333, + "test_time": 13562.297078, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000930, + "ave_all_frame_psnr": 37.586121, + "ave_all_frame_msssim": 0.978344, + "ave_all_frame_psnr_y": 35.913034, + "ave_all_frame_psnr_u": 42.351289, + "ave_all_frame_psnr_v": 42.859472, + "ave_all_frame_msssim_y": 0.975832, + "ave_all_frame_msssim_u": 0.984428, + "ave_all_frame_msssim_v": 0.987333, + "qp": 40, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "043": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000673, + "ave_i_frame_psnr": 36.232111, + "ave_i_frame_msssim": 0.970916, + "ave_i_frame_psnr_y": 34.325943, + "ave_i_frame_psnr_u": 41.510205, + "ave_i_frame_psnr_v": 42.391026, + "ave_i_frame_msssim_y": 0.966502, + "ave_i_frame_msssim_u": 0.981897, + "ave_i_frame_msssim_v": 0.986417, + "test_time": 11281.091234, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000673, + "ave_all_frame_psnr": 36.232111, + "ave_all_frame_msssim": 0.970916, + "ave_all_frame_psnr_y": 34.325943, + "ave_all_frame_psnr_u": 41.510205, + "ave_all_frame_psnr_v": 42.391026, + "ave_all_frame_msssim_y": 0.966502, + "ave_all_frame_msssim_u": 0.981897, + "ave_all_frame_msssim_v": 0.986417, + "qp": 43, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "046": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000490, + "ave_i_frame_psnr": 34.687501, + "ave_i_frame_msssim": 0.960966, + "ave_i_frame_psnr_y": 32.740730, + "ave_i_frame_psnr_u": 40.137862, + "ave_i_frame_psnr_v": 40.917769, + "ave_i_frame_msssim_y": 0.955346, + "ave_i_frame_msssim_u": 0.975823, + "ave_i_frame_msssim_v": 0.979832, + "test_time": 9821.317756, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000490, + "ave_all_frame_psnr": 34.687501, + "ave_all_frame_msssim": 0.960966, + "ave_all_frame_psnr_y": 32.740730, + "ave_all_frame_psnr_u": 40.137862, + "ave_all_frame_psnr_v": 40.917769, + "ave_all_frame_msssim_y": 0.955346, + "ave_all_frame_msssim_u": 0.975823, + "ave_all_frame_msssim_v": 0.979832, + "qp": 46, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + }, + "049": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000365, + "ave_i_frame_psnr": 33.095785, + "ave_i_frame_msssim": 0.949109, + "ave_i_frame_psnr_y": 31.188010, + "ave_i_frame_psnr_u": 38.281032, + "ave_i_frame_psnr_v": 39.357191, + "ave_i_frame_msssim_y": 0.942482, + "ave_i_frame_msssim_u": 0.965525, + "ave_i_frame_msssim_v": 0.972451, + "test_time": 8393.244688, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000365, + "ave_all_frame_psnr": 33.095785, + "ave_all_frame_msssim": 0.949109, + "ave_all_frame_psnr_y": 31.188010, + "ave_all_frame_psnr_u": 38.281032, + "ave_all_frame_psnr_v": 39.357191, + "ave_all_frame_msssim_y": 0.942482, + "ave_all_frame_msssim_u": 0.965525, + "ave_all_frame_msssim_v": 0.972451, + "qp": 49, + "ds_name": "HEVC_E", + "seq_name": "Johnny_1280x720_60.yuv" + } + }, + "KristenAndSara_1280x720_60.yuv": { + "022": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.025251, + "ave_i_frame_psnr": 44.435559, + "ave_i_frame_msssim": 0.995011, + "ave_i_frame_psnr_y": 43.354036, + "ave_i_frame_psnr_u": 47.252649, + "ave_i_frame_psnr_v": 48.107609, + "ave_i_frame_msssim_y": 0.994670, + "ave_i_frame_msssim_u": 0.995715, + "ave_i_frame_msssim_v": 0.996353, + "test_time": 89257.424911, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.025251, + "ave_all_frame_psnr": 44.435559, + "ave_all_frame_msssim": 0.995011, + "ave_all_frame_psnr_y": 43.354036, + "ave_all_frame_psnr_u": 47.252649, + "ave_all_frame_psnr_v": 48.107609, + "ave_all_frame_msssim_y": 0.994670, + "ave_all_frame_msssim_u": 0.995715, + "ave_all_frame_msssim_v": 0.996353, + "qp": 22, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "025": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013157, + "ave_i_frame_psnr": 43.404594, + "ave_i_frame_msssim": 0.993797, + "ave_i_frame_psnr_y": 42.269505, + "ave_i_frame_psnr_u": 46.425241, + "ave_i_frame_psnr_v": 47.194481, + "ave_i_frame_msssim_y": 0.993394, + "ave_i_frame_msssim_u": 0.994662, + "ave_i_frame_msssim_v": 0.995348, + "test_time": 64161.221615, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013157, + "ave_all_frame_psnr": 43.404594, + "ave_all_frame_msssim": 0.993797, + "ave_all_frame_psnr_y": 42.269505, + "ave_all_frame_psnr_u": 46.425241, + "ave_all_frame_psnr_v": 47.194481, + "ave_all_frame_msssim_y": 0.993394, + "ave_all_frame_msssim_u": 0.994662, + "ave_all_frame_msssim_v": 0.995348, + "qp": 25, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "028": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007664, + "ave_i_frame_psnr": 42.256037, + "ave_i_frame_msssim": 0.992010, + "ave_i_frame_psnr_y": 41.068209, + "ave_i_frame_psnr_u": 45.453239, + "ave_i_frame_psnr_v": 46.185805, + "ave_i_frame_msssim_y": 0.991511, + "ave_i_frame_msssim_u": 0.993134, + "ave_i_frame_msssim_v": 0.993879, + "test_time": 46012.137995, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007664, + "ave_all_frame_psnr": 42.256037, + "ave_all_frame_msssim": 0.992010, + "ave_all_frame_psnr_y": 41.068209, + "ave_all_frame_psnr_u": 45.453239, + "ave_all_frame_psnr_v": 46.185805, + "ave_all_frame_msssim_y": 0.991511, + "ave_all_frame_msssim_u": 0.993134, + "ave_all_frame_msssim_v": 0.993879, + "qp": 28, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "031": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004715, + "ave_i_frame_psnr": 40.947816, + "ave_i_frame_msssim": 0.989406, + "ave_i_frame_psnr_y": 39.708922, + "ave_i_frame_psnr_u": 44.349591, + "ave_i_frame_psnr_v": 44.979405, + "ave_i_frame_msssim_y": 0.988735, + "ave_i_frame_msssim_u": 0.990994, + "ave_i_frame_msssim_v": 0.991842, + "test_time": 33932.595618, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004715, + "ave_all_frame_psnr": 40.947816, + "ave_all_frame_msssim": 0.989406, + "ave_all_frame_psnr_y": 39.708922, + "ave_all_frame_psnr_u": 44.349591, + "ave_all_frame_psnr_v": 44.979405, + "ave_all_frame_msssim_y": 0.988735, + "ave_all_frame_msssim_u": 0.990994, + "ave_all_frame_msssim_v": 0.991842, + "qp": 31, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "034": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003162, + "ave_i_frame_psnr": 39.610920, + "ave_i_frame_msssim": 0.985908, + "ave_i_frame_psnr_y": 38.291145, + "ave_i_frame_psnr_u": 43.234478, + "ave_i_frame_psnr_v": 43.906017, + "ave_i_frame_msssim_y": 0.984974, + "ave_i_frame_msssim_u": 0.988311, + "ave_i_frame_msssim_v": 0.989112, + "test_time": 26398.188916, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003162, + "ave_all_frame_psnr": 39.610920, + "ave_all_frame_msssim": 0.985908, + "ave_all_frame_psnr_y": 38.291145, + "ave_all_frame_psnr_u": 43.234478, + "ave_all_frame_psnr_v": 43.906017, + "ave_all_frame_msssim_y": 0.984974, + "ave_all_frame_msssim_u": 0.988311, + "ave_all_frame_msssim_v": 0.989112, + "qp": 34, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "037": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002180, + "ave_i_frame_psnr": 38.237991, + "ave_i_frame_msssim": 0.981237, + "ave_i_frame_psnr_y": 36.803592, + "ave_i_frame_psnr_u": 42.162788, + "ave_i_frame_psnr_v": 42.919591, + "ave_i_frame_msssim_y": 0.979811, + "ave_i_frame_msssim_u": 0.984632, + "ave_i_frame_msssim_v": 0.986401, + "test_time": 21319.764812, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002180, + "ave_all_frame_psnr": 38.237991, + "ave_all_frame_msssim": 0.981237, + "ave_all_frame_psnr_y": 36.803592, + "ave_all_frame_psnr_u": 42.162788, + "ave_all_frame_psnr_v": 42.919591, + "ave_all_frame_msssim_y": 0.979811, + "ave_all_frame_msssim_u": 0.984632, + "ave_all_frame_msssim_v": 0.986401, + "qp": 37, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "040": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001524, + "ave_i_frame_psnr": 36.843643, + "ave_i_frame_msssim": 0.975009, + "ave_i_frame_psnr_y": 35.217190, + "ave_i_frame_psnr_u": 41.280883, + "ave_i_frame_psnr_v": 42.165123, + "ave_i_frame_msssim_y": 0.972538, + "ave_i_frame_msssim_u": 0.981305, + "ave_i_frame_msssim_v": 0.983541, + "test_time": 17259.523679, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001524, + "ave_all_frame_psnr": 36.843643, + "ave_all_frame_msssim": 0.975009, + "ave_all_frame_psnr_y": 35.217190, + "ave_all_frame_psnr_u": 41.280883, + "ave_all_frame_psnr_v": 42.165123, + "ave_all_frame_msssim_y": 0.972538, + "ave_all_frame_msssim_u": 0.981305, + "ave_all_frame_msssim_v": 0.983541, + "qp": 40, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "043": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.001089, + "ave_i_frame_psnr": 35.434314, + "ave_i_frame_msssim": 0.966802, + "ave_i_frame_psnr_y": 33.554293, + "ave_i_frame_psnr_u": 40.616158, + "ave_i_frame_psnr_v": 41.532601, + "ave_i_frame_msssim_y": 0.962681, + "ave_i_frame_msssim_u": 0.977798, + "ave_i_frame_msssim_v": 0.980531, + "test_time": 13892.635324, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.001089, + "ave_all_frame_psnr": 35.434314, + "ave_all_frame_msssim": 0.966802, + "ave_all_frame_psnr_y": 33.554293, + "ave_all_frame_psnr_u": 40.616158, + "ave_all_frame_psnr_v": 41.532601, + "ave_all_frame_msssim_y": 0.962681, + "ave_all_frame_msssim_u": 0.977798, + "ave_all_frame_msssim_v": 0.980531, + "qp": 43, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "046": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000769, + "ave_i_frame_psnr": 33.679907, + "ave_i_frame_msssim": 0.953858, + "ave_i_frame_psnr_y": 31.715219, + "ave_i_frame_psnr_u": 39.286126, + "ave_i_frame_psnr_v": 39.861822, + "ave_i_frame_msssim_y": 0.948310, + "ave_i_frame_msssim_u": 0.970877, + "ave_i_frame_msssim_v": 0.970129, + "test_time": 11790.960306, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000769, + "ave_all_frame_psnr": 33.679907, + "ave_all_frame_msssim": 0.953858, + "ave_all_frame_psnr_y": 31.715219, + "ave_all_frame_psnr_u": 39.286126, + "ave_all_frame_psnr_v": 39.861822, + "ave_all_frame_msssim_y": 0.948310, + "ave_all_frame_msssim_u": 0.970877, + "ave_all_frame_msssim_v": 0.970129, + "qp": 46, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + }, + "049": { + "frame_pixel_num": 921600, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.000548, + "ave_i_frame_psnr": 31.974030, + "ave_i_frame_msssim": 0.937187, + "ave_i_frame_psnr_y": 29.929390, + "ave_i_frame_psnr_u": 37.791848, + "ave_i_frame_psnr_v": 38.424047, + "ave_i_frame_msssim_y": 0.929392, + "ave_i_frame_msssim_u": 0.960934, + "ave_i_frame_msssim_v": 0.960213, + "test_time": 9818.390726, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.000548, + "ave_all_frame_psnr": 31.974030, + "ave_all_frame_msssim": 0.937187, + "ave_all_frame_psnr_y": 29.929390, + "ave_all_frame_psnr_u": 37.791848, + "ave_all_frame_psnr_v": 38.424047, + "ave_all_frame_msssim_y": 0.929392, + "ave_all_frame_msssim_u": 0.960934, + "ave_all_frame_msssim_v": 0.960213, + "qp": 49, + "ds_name": "HEVC_E", + "seq_name": "KristenAndSara_1280x720_60.yuv" + } + } + }, + "HEVC_C": { + "BQMall_832x480_60.yuv": { + "022": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.126541, + "ave_i_frame_psnr": 41.023486, + "ave_i_frame_msssim": 0.994769, + "ave_i_frame_psnr_y": 40.124732, + "ave_i_frame_psnr_u": 43.040379, + "ave_i_frame_psnr_v": 44.399119, + "ave_i_frame_msssim_y": 0.995338, + "ave_i_frame_msssim_u": 0.992126, + "ave_i_frame_msssim_v": 0.993996, + "test_time": 71952.667172, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.126541, + "ave_all_frame_psnr": 41.023486, + "ave_all_frame_msssim": 0.994769, + "ave_all_frame_psnr_y": 40.124732, + "ave_all_frame_psnr_u": 43.040379, + "ave_all_frame_psnr_v": 44.399119, + "ave_all_frame_msssim_y": 0.995338, + "ave_all_frame_msssim_u": 0.992126, + "ave_all_frame_msssim_v": 0.993996, + "qp": 22, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "025": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.075489, + "ave_i_frame_psnr": 39.440472, + "ave_i_frame_msssim": 0.992355, + "ave_i_frame_psnr_y": 38.440976, + "ave_i_frame_psnr_u": 41.872616, + "ave_i_frame_psnr_v": 43.005304, + "ave_i_frame_msssim_y": 0.993187, + "ave_i_frame_msssim_u": 0.988653, + "ave_i_frame_msssim_v": 0.991064, + "test_time": 62047.926787, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.075489, + "ave_all_frame_psnr": 39.440472, + "ave_all_frame_msssim": 0.992355, + "ave_all_frame_psnr_y": 38.440976, + "ave_all_frame_psnr_u": 41.872616, + "ave_all_frame_psnr_v": 43.005304, + "ave_all_frame_msssim_y": 0.993187, + "ave_all_frame_msssim_u": 0.988653, + "ave_all_frame_msssim_v": 0.991064, + "qp": 25, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "028": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.046603, + "ave_i_frame_psnr": 37.810373, + "ave_i_frame_msssim": 0.988662, + "ave_i_frame_psnr_y": 36.683040, + "ave_i_frame_psnr_u": 40.710128, + "ave_i_frame_psnr_v": 41.674615, + "ave_i_frame_msssim_y": 0.989766, + "ave_i_frame_msssim_u": 0.983784, + "ave_i_frame_msssim_v": 0.986912, + "test_time": 52247.550670, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.046603, + "ave_all_frame_psnr": 37.810373, + "ave_all_frame_msssim": 0.988662, + "ave_all_frame_psnr_y": 36.683040, + "ave_all_frame_psnr_u": 40.710128, + "ave_all_frame_psnr_v": 41.674615, + "ave_all_frame_msssim_y": 0.989766, + "ave_all_frame_msssim_u": 0.983784, + "ave_all_frame_msssim_v": 0.986912, + "qp": 28, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "031": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.029450, + "ave_i_frame_psnr": 36.166446, + "ave_i_frame_msssim": 0.983170, + "ave_i_frame_psnr_y": 34.887117, + "ave_i_frame_psnr_u": 39.583243, + "ave_i_frame_psnr_v": 40.425619, + "ave_i_frame_msssim_y": 0.984460, + "ave_i_frame_msssim_u": 0.977181, + "ave_i_frame_msssim_v": 0.981419, + "test_time": 41084.516518, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.029450, + "ave_all_frame_psnr": 36.166446, + "ave_all_frame_msssim": 0.983170, + "ave_all_frame_psnr_y": 34.887117, + "ave_all_frame_psnr_u": 39.583243, + "ave_all_frame_psnr_v": 40.425619, + "ave_all_frame_msssim_y": 0.984460, + "ave_all_frame_msssim_u": 0.977181, + "ave_all_frame_msssim_v": 0.981419, + "qp": 31, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "034": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.019713, + "ave_i_frame_psnr": 34.644474, + "ave_i_frame_msssim": 0.975537, + "ave_i_frame_psnr_y": 33.266521, + "ave_i_frame_psnr_u": 38.393543, + "ave_i_frame_psnr_v": 39.163120, + "ave_i_frame_msssim_y": 0.977248, + "ave_i_frame_msssim_u": 0.967518, + "ave_i_frame_msssim_v": 0.973289, + "test_time": 31972.734406, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.019713, + "ave_all_frame_psnr": 34.644474, + "ave_all_frame_msssim": 0.975537, + "ave_all_frame_psnr_y": 33.266521, + "ave_all_frame_psnr_u": 38.393543, + "ave_all_frame_psnr_v": 39.163120, + "ave_all_frame_msssim_y": 0.977248, + "ave_all_frame_msssim_u": 0.967518, + "ave_all_frame_msssim_v": 0.973289, + "qp": 34, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "037": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013282, + "ave_i_frame_psnr": 33.272379, + "ave_i_frame_msssim": 0.966388, + "ave_i_frame_psnr_y": 31.643728, + "ave_i_frame_psnr_u": 37.753190, + "ave_i_frame_psnr_v": 38.563471, + "ave_i_frame_msssim_y": 0.966806, + "ave_i_frame_msssim_u": 0.961412, + "ave_i_frame_msssim_v": 0.968860, + "test_time": 25523.309527, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013282, + "ave_all_frame_psnr": 33.272379, + "ave_all_frame_msssim": 0.966388, + "ave_all_frame_psnr_y": 31.643728, + "ave_all_frame_psnr_u": 37.753190, + "ave_all_frame_psnr_v": 38.563471, + "ave_all_frame_msssim_y": 0.966806, + "ave_all_frame_msssim_u": 0.961412, + "ave_all_frame_msssim_v": 0.968860, + "qp": 37, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "040": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008893, + "ave_i_frame_psnr": 31.821674, + "ave_i_frame_msssim": 0.952953, + "ave_i_frame_psnr_y": 30.013207, + "ave_i_frame_psnr_u": 36.894179, + "ave_i_frame_psnr_v": 37.599973, + "ave_i_frame_msssim_y": 0.951888, + "ave_i_frame_msssim_u": 0.951976, + "ave_i_frame_msssim_v": 0.960321, + "test_time": 19971.034952, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008893, + "ave_all_frame_psnr": 31.821674, + "ave_all_frame_msssim": 0.952953, + "ave_all_frame_psnr_y": 30.013207, + "ave_all_frame_psnr_u": 36.894179, + "ave_all_frame_psnr_v": 37.599973, + "ave_all_frame_msssim_y": 0.951888, + "ave_all_frame_msssim_u": 0.951976, + "ave_all_frame_msssim_v": 0.960321, + "qp": 40, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "043": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005958, + "ave_i_frame_psnr": 30.412596, + "ave_i_frame_msssim": 0.934627, + "ave_i_frame_psnr_y": 28.401799, + "ave_i_frame_psnr_u": 36.203799, + "ave_i_frame_psnr_v": 36.686177, + "ave_i_frame_msssim_y": 0.930716, + "ave_i_frame_msssim_u": 0.942353, + "ave_i_frame_msssim_v": 0.950365, + "test_time": 15750.423399, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005958, + "ave_all_frame_psnr": 30.412596, + "ave_all_frame_msssim": 0.934627, + "ave_all_frame_psnr_y": 28.401799, + "ave_all_frame_psnr_u": 36.203799, + "ave_all_frame_psnr_v": 36.686177, + "ave_all_frame_msssim_y": 0.930716, + "ave_all_frame_msssim_u": 0.942353, + "ave_all_frame_msssim_v": 0.950365, + "qp": 43, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "046": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003951, + "ave_i_frame_psnr": 28.921564, + "ave_i_frame_msssim": 0.907586, + "ave_i_frame_psnr_y": 26.826158, + "ave_i_frame_psnr_u": 34.988516, + "ave_i_frame_psnr_v": 35.427043, + "ave_i_frame_msssim_y": 0.901130, + "ave_i_frame_msssim_u": 0.922364, + "ave_i_frame_msssim_v": 0.931549, + "test_time": 12271.947601, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003951, + "ave_all_frame_psnr": 28.921564, + "ave_all_frame_msssim": 0.907586, + "ave_all_frame_psnr_y": 26.826158, + "ave_all_frame_psnr_u": 34.988516, + "ave_all_frame_psnr_v": 35.427043, + "ave_all_frame_msssim_y": 0.901130, + "ave_all_frame_msssim_u": 0.922364, + "ave_all_frame_msssim_v": 0.931549, + "qp": 46, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + }, + "049": { + "frame_pixel_num": 399360, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002643, + "ave_i_frame_psnr": 27.474866, + "ave_i_frame_msssim": 0.871223, + "ave_i_frame_psnr_y": 25.305482, + "ave_i_frame_psnr_u": 33.870254, + "ave_i_frame_psnr_v": 34.095785, + "ave_i_frame_msssim_y": 0.860526, + "ave_i_frame_msssim_u": 0.899957, + "ave_i_frame_msssim_v": 0.906671, + "test_time": 9653.699746, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002643, + "ave_all_frame_psnr": 27.474866, + "ave_all_frame_msssim": 0.871223, + "ave_all_frame_psnr_y": 25.305482, + "ave_all_frame_psnr_u": 33.870254, + "ave_all_frame_psnr_v": 34.095785, + "ave_all_frame_msssim_y": 0.860526, + "ave_all_frame_msssim_u": 0.899957, + "ave_all_frame_msssim_v": 0.906671, + "qp": 49, + "ds_name": "HEVC_C", + "seq_name": "BQMall_832x480_60.yuv" + } + }, + "BasketballDrill_832x480_50.yuv": { + "022": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.133811, + "ave_i_frame_psnr": 41.578748, + "ave_i_frame_msssim": 0.994377, + "ave_i_frame_psnr_y": 40.935934, + "ave_i_frame_psnr_u": 43.124842, + "ave_i_frame_psnr_v": 43.889539, + "ave_i_frame_msssim_y": 0.994337, + "ave_i_frame_msssim_u": 0.993619, + "ave_i_frame_msssim_v": 0.995375, + "test_time": 74189.247890, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.133811, + "ave_all_frame_psnr": 41.578748, + "ave_all_frame_msssim": 0.994377, + "ave_all_frame_psnr_y": 40.935934, + "ave_all_frame_psnr_u": 43.124842, + "ave_all_frame_psnr_v": 43.889539, + "ave_all_frame_msssim_y": 0.994337, + "ave_all_frame_msssim_u": 0.993619, + "ave_all_frame_msssim_v": 0.995375, + "qp": 22, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "025": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.082829, + "ave_i_frame_psnr": 39.835001, + "ave_i_frame_msssim": 0.991158, + "ave_i_frame_psnr_y": 39.099572, + "ave_i_frame_psnr_u": 41.767660, + "ave_i_frame_psnr_v": 42.314920, + "ave_i_frame_msssim_y": 0.990850, + "ave_i_frame_msssim_u": 0.990919, + "ave_i_frame_msssim_v": 0.993245, + "test_time": 65114.597185, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.082829, + "ave_all_frame_psnr": 39.835001, + "ave_all_frame_msssim": 0.991158, + "ave_all_frame_psnr_y": 39.099572, + "ave_all_frame_psnr_u": 41.767660, + "ave_all_frame_psnr_v": 42.314920, + "ave_all_frame_msssim_y": 0.990850, + "ave_all_frame_msssim_u": 0.990919, + "ave_all_frame_msssim_v": 0.993245, + "qp": 25, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "028": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.051562, + "ave_i_frame_psnr": 38.066515, + "ave_i_frame_msssim": 0.985989, + "ave_i_frame_psnr_y": 37.224015, + "ave_i_frame_psnr_u": 40.421729, + "ave_i_frame_psnr_v": 40.766305, + "ave_i_frame_msssim_y": 0.985095, + "ave_i_frame_msssim_u": 0.987071, + "ave_i_frame_msssim_v": 0.990271, + "test_time": 55261.233874, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.051562, + "ave_all_frame_psnr": 38.066515, + "ave_all_frame_msssim": 0.985989, + "ave_all_frame_psnr_y": 37.224015, + "ave_all_frame_psnr_u": 40.421729, + "ave_all_frame_psnr_v": 40.766305, + "ave_all_frame_msssim_y": 0.985095, + "ave_all_frame_msssim_u": 0.987071, + "ave_all_frame_msssim_v": 0.990271, + "qp": 28, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "031": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.032381, + "ave_i_frame_psnr": 36.430075, + "ave_i_frame_msssim": 0.978486, + "ave_i_frame_psnr_y": 35.428719, + "ave_i_frame_psnr_u": 39.313758, + "ave_i_frame_psnr_v": 39.554531, + "ave_i_frame_msssim_y": 0.976288, + "ave_i_frame_msssim_u": 0.983121, + "ave_i_frame_msssim_v": 0.987039, + "test_time": 43028.909328, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.032381, + "ave_all_frame_psnr": 36.430075, + "ave_all_frame_msssim": 0.978486, + "ave_all_frame_psnr_y": 35.428719, + "ave_all_frame_psnr_u": 39.313758, + "ave_all_frame_psnr_v": 39.554531, + "ave_all_frame_msssim_y": 0.976288, + "ave_all_frame_msssim_u": 0.983121, + "ave_all_frame_msssim_v": 0.987039, + "qp": 31, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "034": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.021852, + "ave_i_frame_psnr": 34.967784, + "ave_i_frame_msssim": 0.968398, + "ave_i_frame_psnr_y": 33.896585, + "ave_i_frame_psnr_u": 38.150927, + "ave_i_frame_psnr_v": 38.211836, + "ave_i_frame_msssim_y": 0.964551, + "ave_i_frame_msssim_u": 0.977785, + "ave_i_frame_msssim_v": 0.982097, + "test_time": 33288.694383, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.021852, + "ave_all_frame_psnr": 34.967784, + "ave_all_frame_msssim": 0.968398, + "ave_all_frame_psnr_y": 33.896585, + "ave_all_frame_psnr_u": 38.150927, + "ave_all_frame_psnr_v": 38.211836, + "ave_all_frame_msssim_y": 0.964551, + "ave_all_frame_msssim_u": 0.977785, + "ave_all_frame_msssim_v": 0.982097, + "qp": 34, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "037": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014833, + "ave_i_frame_psnr": 33.574579, + "ave_i_frame_msssim": 0.955176, + "ave_i_frame_psnr_y": 32.418671, + "ave_i_frame_psnr_u": 37.099544, + "ave_i_frame_psnr_v": 36.985059, + "ave_i_frame_msssim_y": 0.948826, + "ave_i_frame_msssim_u": 0.972410, + "ave_i_frame_msssim_v": 0.976042, + "test_time": 25706.730178, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014833, + "ave_all_frame_psnr": 33.574579, + "ave_all_frame_msssim": 0.955176, + "ave_all_frame_psnr_y": 32.418671, + "ave_all_frame_psnr_u": 37.099544, + "ave_all_frame_psnr_v": 36.985059, + "ave_all_frame_msssim_y": 0.948826, + "ave_all_frame_msssim_u": 0.972410, + "ave_all_frame_msssim_v": 0.976042, + "qp": 37, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "040": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009943, + "ave_i_frame_psnr": 32.208366, + "ave_i_frame_msssim": 0.938081, + "ave_i_frame_psnr_y": 30.974027, + "ave_i_frame_psnr_u": 36.051360, + "ave_i_frame_psnr_v": 35.771410, + "ave_i_frame_msssim_y": 0.928642, + "ave_i_frame_msssim_u": 0.964014, + "ave_i_frame_msssim_v": 0.968776, + "test_time": 18659.356661, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009943, + "ave_all_frame_psnr": 32.208366, + "ave_all_frame_msssim": 0.938081, + "ave_all_frame_psnr_y": 30.974027, + "ave_all_frame_psnr_u": 36.051360, + "ave_all_frame_psnr_v": 35.771410, + "ave_all_frame_msssim_y": 0.928642, + "ave_all_frame_msssim_u": 0.964014, + "ave_all_frame_msssim_v": 0.968776, + "qp": 40, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "043": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006666, + "ave_i_frame_psnr": 30.827807, + "ave_i_frame_msssim": 0.914872, + "ave_i_frame_psnr_y": 29.491597, + "ave_i_frame_psnr_u": 35.111118, + "ave_i_frame_psnr_v": 34.561757, + "ave_i_frame_msssim_y": 0.901627, + "ave_i_frame_msssim_u": 0.952424, + "ave_i_frame_msssim_v": 0.956793, + "test_time": 13824.327190, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006666, + "ave_all_frame_psnr": 30.827807, + "ave_all_frame_msssim": 0.914872, + "ave_all_frame_psnr_y": 29.491597, + "ave_all_frame_psnr_u": 35.111118, + "ave_all_frame_psnr_v": 34.561757, + "ave_all_frame_msssim_y": 0.901627, + "ave_all_frame_msssim_u": 0.952424, + "ave_all_frame_msssim_v": 0.956793, + "qp": 43, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "046": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004420, + "ave_i_frame_psnr": 29.371154, + "ave_i_frame_msssim": 0.888954, + "ave_i_frame_psnr_y": 28.000699, + "ave_i_frame_psnr_u": 33.758487, + "ave_i_frame_psnr_v": 33.206552, + "ave_i_frame_msssim_y": 0.872658, + "ave_i_frame_msssim_u": 0.934724, + "ave_i_frame_msssim_v": 0.940960, + "test_time": 10423.929155, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004420, + "ave_all_frame_psnr": 29.371154, + "ave_all_frame_msssim": 0.888954, + "ave_all_frame_psnr_y": 28.000699, + "ave_all_frame_psnr_u": 33.758487, + "ave_all_frame_psnr_v": 33.206552, + "ave_all_frame_msssim_y": 0.872658, + "ave_all_frame_msssim_u": 0.934724, + "ave_all_frame_msssim_v": 0.940960, + "qp": 46, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + }, + "049": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002896, + "ave_i_frame_psnr": 27.704969, + "ave_i_frame_msssim": 0.845684, + "ave_i_frame_psnr_y": 26.331521, + "ave_i_frame_psnr_u": 32.171439, + "ave_i_frame_psnr_v": 31.479190, + "ave_i_frame_msssim_y": 0.826744, + "ave_i_frame_msssim_u": 0.904273, + "ave_i_frame_msssim_v": 0.900734, + "test_time": 7853.680946, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002896, + "ave_all_frame_psnr": 27.704969, + "ave_all_frame_msssim": 0.845684, + "ave_all_frame_psnr_y": 26.331521, + "ave_all_frame_psnr_u": 32.171439, + "ave_all_frame_psnr_v": 31.479190, + "ave_all_frame_msssim_y": 0.826744, + "ave_all_frame_msssim_u": 0.904273, + "ave_all_frame_msssim_v": 0.900734, + "qp": 49, + "ds_name": "HEVC_C", + "seq_name": "BasketballDrill_832x480_50.yuv" + } + }, + "PartyScene_832x480_50.yuv": { + "022": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.306261, + "ave_i_frame_psnr": 39.076659, + "ave_i_frame_msssim": 0.995079, + "ave_i_frame_psnr_y": 38.330680, + "ave_i_frame_psnr_u": 40.857064, + "ave_i_frame_psnr_v": 41.772129, + "ave_i_frame_msssim_y": 0.996073, + "ave_i_frame_msssim_u": 0.991220, + "ave_i_frame_msssim_v": 0.992970, + "test_time": 80271.259661, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.306261, + "ave_all_frame_psnr": 39.076659, + "ave_all_frame_msssim": 0.995079, + "ave_all_frame_psnr_y": 38.330680, + "ave_all_frame_psnr_u": 40.857064, + "ave_all_frame_psnr_v": 41.772129, + "ave_all_frame_msssim_y": 0.996073, + "ave_all_frame_msssim_u": 0.991220, + "ave_all_frame_msssim_v": 0.992970, + "qp": 22, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "025": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.177340, + "ave_i_frame_psnr": 36.929583, + "ave_i_frame_msssim": 0.991916, + "ave_i_frame_psnr_y": 36.011119, + "ave_i_frame_psnr_u": 39.283230, + "ave_i_frame_psnr_v": 40.086716, + "ave_i_frame_msssim_y": 0.993323, + "ave_i_frame_msssim_u": 0.986551, + "ave_i_frame_msssim_v": 0.988842, + "test_time": 68442.547448, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.177340, + "ave_all_frame_psnr": 36.929583, + "ave_all_frame_msssim": 0.991916, + "ave_all_frame_psnr_y": 36.011119, + "ave_all_frame_psnr_u": 39.283230, + "ave_all_frame_psnr_v": 40.086716, + "ave_all_frame_msssim_y": 0.993323, + "ave_all_frame_msssim_u": 0.986551, + "ave_all_frame_msssim_v": 0.988842, + "qp": 25, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "028": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.102868, + "ave_i_frame_psnr": 34.911566, + "ave_i_frame_msssim": 0.986919, + "ave_i_frame_psnr_y": 33.811958, + "ave_i_frame_psnr_u": 37.862320, + "ave_i_frame_psnr_v": 38.558455, + "ave_i_frame_msssim_y": 0.988692, + "ave_i_frame_msssim_u": 0.980244, + "ave_i_frame_msssim_v": 0.982954, + "test_time": 59265.913416, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.102868, + "ave_all_frame_psnr": 34.911566, + "ave_all_frame_msssim": 0.986919, + "ave_all_frame_psnr_y": 33.811958, + "ave_all_frame_psnr_u": 37.862320, + "ave_all_frame_psnr_v": 38.558455, + "ave_all_frame_msssim_y": 0.988692, + "ave_all_frame_msssim_u": 0.980244, + "ave_all_frame_msssim_v": 0.982954, + "qp": 28, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "031": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.060123, + "ave_i_frame_psnr": 33.050516, + "ave_i_frame_msssim": 0.979461, + "ave_i_frame_psnr_y": 31.738877, + "ave_i_frame_psnr_u": 36.669623, + "ave_i_frame_psnr_v": 37.301244, + "ave_i_frame_msssim_y": 0.981228, + "ave_i_frame_msssim_u": 0.972649, + "ave_i_frame_msssim_v": 0.975674, + "test_time": 49668.707927, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.060123, + "ave_all_frame_psnr": 33.050516, + "ave_all_frame_msssim": 0.979461, + "ave_all_frame_psnr_y": 31.738877, + "ave_all_frame_psnr_u": 36.669623, + "ave_all_frame_psnr_v": 37.301244, + "ave_all_frame_msssim_y": 0.981228, + "ave_all_frame_msssim_u": 0.972649, + "ave_all_frame_msssim_v": 0.975674, + "qp": 31, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "034": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.037446, + "ave_i_frame_psnr": 31.375619, + "ave_i_frame_msssim": 0.968765, + "ave_i_frame_psnr_y": 29.915214, + "ave_i_frame_psnr_u": 35.471416, + "ave_i_frame_psnr_v": 36.042252, + "ave_i_frame_msssim_y": 0.970450, + "ave_i_frame_msssim_u": 0.961863, + "ave_i_frame_msssim_v": 0.965552, + "test_time": 37665.554852, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.037446, + "ave_all_frame_psnr": 31.375619, + "ave_all_frame_msssim": 0.968765, + "ave_all_frame_psnr_y": 29.915214, + "ave_all_frame_psnr_u": 35.471416, + "ave_all_frame_psnr_v": 36.042252, + "ave_all_frame_msssim_y": 0.970450, + "ave_all_frame_msssim_u": 0.961863, + "ave_all_frame_msssim_v": 0.965552, + "qp": 34, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "037": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022547, + "ave_i_frame_psnr": 29.875820, + "ave_i_frame_msssim": 0.954037, + "ave_i_frame_psnr_y": 28.147590, + "ave_i_frame_psnr_u": 34.690088, + "ave_i_frame_psnr_v": 35.430931, + "ave_i_frame_msssim_y": 0.953289, + "ave_i_frame_msssim_u": 0.953595, + "ave_i_frame_msssim_v": 0.958962, + "test_time": 29918.279619, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022547, + "ave_all_frame_psnr": 29.875820, + "ave_all_frame_msssim": 0.954037, + "ave_all_frame_psnr_y": 28.147590, + "ave_all_frame_psnr_u": 34.690088, + "ave_all_frame_psnr_v": 35.430931, + "ave_all_frame_msssim_y": 0.953289, + "ave_all_frame_msssim_u": 0.953595, + "ave_all_frame_msssim_v": 0.958962, + "qp": 37, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "040": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013123, + "ave_i_frame_psnr": 28.425603, + "ave_i_frame_msssim": 0.931214, + "ave_i_frame_psnr_y": 26.494610, + "ave_i_frame_psnr_u": 33.873593, + "ave_i_frame_psnr_v": 34.563566, + "ave_i_frame_msssim_y": 0.926840, + "ave_i_frame_msssim_u": 0.941376, + "ave_i_frame_msssim_v": 0.947293, + "test_time": 22883.046766, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013123, + "ave_all_frame_psnr": 28.425603, + "ave_all_frame_msssim": 0.931214, + "ave_all_frame_psnr_y": 26.494610, + "ave_all_frame_psnr_u": 33.873593, + "ave_all_frame_psnr_v": 34.563566, + "ave_all_frame_msssim_y": 0.926840, + "ave_all_frame_msssim_u": 0.941376, + "ave_all_frame_msssim_v": 0.947293, + "qp": 40, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "043": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.007468, + "ave_i_frame_psnr": 27.117576, + "ave_i_frame_msssim": 0.901506, + "ave_i_frame_psnr_y": 24.991237, + "ave_i_frame_psnr_u": 33.157604, + "ave_i_frame_psnr_v": 33.835580, + "ave_i_frame_msssim_y": 0.891524, + "ave_i_frame_msssim_u": 0.928012, + "ave_i_frame_msssim_v": 0.934895, + "test_time": 17261.382119, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.007468, + "ave_all_frame_psnr": 27.117576, + "ave_all_frame_msssim": 0.901506, + "ave_all_frame_psnr_y": 24.991237, + "ave_all_frame_psnr_u": 33.157604, + "ave_all_frame_psnr_v": 33.835580, + "ave_all_frame_msssim_y": 0.891524, + "ave_all_frame_msssim_u": 0.928012, + "ave_all_frame_msssim_v": 0.934895, + "qp": 43, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "046": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004154, + "ave_i_frame_psnr": 25.853632, + "ave_i_frame_msssim": 0.858082, + "ave_i_frame_psnr_y": 23.658186, + "ave_i_frame_psnr_u": 32.132005, + "ave_i_frame_psnr_v": 32.747938, + "ave_i_frame_msssim_y": 0.841288, + "ave_i_frame_msssim_u": 0.904621, + "ave_i_frame_msssim_v": 0.912302, + "test_time": 12879.771523, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004154, + "ave_all_frame_psnr": 25.853632, + "ave_all_frame_msssim": 0.858082, + "ave_all_frame_psnr_y": 23.658186, + "ave_all_frame_psnr_u": 32.132005, + "ave_all_frame_psnr_v": 32.747938, + "ave_all_frame_msssim_y": 0.841288, + "ave_all_frame_msssim_u": 0.904621, + "ave_all_frame_msssim_v": 0.912302, + "qp": 46, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + }, + "049": { + "frame_pixel_num": 399360, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.002365, + "ave_i_frame_psnr": 24.715175, + "ave_i_frame_msssim": 0.802524, + "ave_i_frame_psnr_y": 22.490245, + "ave_i_frame_psnr_u": 31.092699, + "ave_i_frame_psnr_v": 31.687227, + "ave_i_frame_msssim_y": 0.776906, + "ave_i_frame_msssim_u": 0.874953, + "ave_i_frame_msssim_v": 0.883809, + "test_time": 9708.933739, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.002365, + "ave_all_frame_psnr": 24.715175, + "ave_all_frame_msssim": 0.802524, + "ave_all_frame_psnr_y": 22.490245, + "ave_all_frame_psnr_u": 31.092699, + "ave_all_frame_psnr_v": 31.687227, + "ave_all_frame_msssim_y": 0.776906, + "ave_all_frame_msssim_u": 0.874953, + "ave_all_frame_msssim_v": 0.883809, + "qp": 49, + "ds_name": "HEVC_C", + "seq_name": "PartyScene_832x480_50.yuv" + } + }, + "RaceHorses_832x480_30.yuv": { + "022": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.376380, + "ave_i_frame_psnr": 40.329098, + "ave_i_frame_msssim": 0.992562, + "ave_i_frame_psnr_y": 39.876809, + "ave_i_frame_psnr_u": 40.953543, + "ave_i_frame_psnr_v": 42.418387, + "ave_i_frame_msssim_y": 0.993317, + "ave_i_frame_msssim_u": 0.990014, + "ave_i_frame_msssim_v": 0.990574, + "test_time": 62159.254373, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.376380, + "ave_all_frame_psnr": 40.329098, + "ave_all_frame_msssim": 0.992562, + "ave_all_frame_psnr_y": 39.876809, + "ave_all_frame_psnr_u": 40.953543, + "ave_all_frame_psnr_v": 42.418387, + "ave_all_frame_msssim_y": 0.993317, + "ave_all_frame_msssim_u": 0.990014, + "ave_all_frame_msssim_v": 0.990574, + "qp": 22, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "025": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.202789, + "ave_i_frame_psnr": 38.202706, + "ave_i_frame_msssim": 0.988157, + "ave_i_frame_psnr_y": 37.559658, + "ave_i_frame_psnr_u": 39.318593, + "ave_i_frame_psnr_v": 40.945110, + "ave_i_frame_msssim_y": 0.989143, + "ave_i_frame_msssim_u": 0.984430, + "ave_i_frame_msssim_v": 0.985971, + "test_time": 52683.813170, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.202789, + "ave_all_frame_psnr": 38.202706, + "ave_all_frame_msssim": 0.988157, + "ave_all_frame_psnr_y": 37.559658, + "ave_all_frame_psnr_u": 39.318593, + "ave_all_frame_psnr_v": 40.945110, + "ave_all_frame_msssim_y": 0.989143, + "ave_all_frame_msssim_u": 0.984430, + "ave_all_frame_msssim_v": 0.985971, + "qp": 25, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "028": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.114657, + "ave_i_frame_psnr": 36.308714, + "ave_i_frame_msssim": 0.981668, + "ave_i_frame_psnr_y": 35.494045, + "ave_i_frame_psnr_u": 37.863906, + "ave_i_frame_psnr_v": 39.641540, + "ave_i_frame_msssim_y": 0.982771, + "ave_i_frame_msssim_u": 0.976389, + "ave_i_frame_msssim_v": 0.980331, + "test_time": 45565.157812, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.114657, + "ave_all_frame_psnr": 36.308714, + "ave_all_frame_msssim": 0.981668, + "ave_all_frame_psnr_y": 35.494045, + "ave_all_frame_psnr_u": 37.863906, + "ave_all_frame_psnr_v": 39.641540, + "ave_all_frame_msssim_y": 0.982771, + "ave_all_frame_msssim_u": 0.976389, + "ave_all_frame_msssim_v": 0.980331, + "qp": 28, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "031": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.068348, + "ave_i_frame_psnr": 34.565298, + "ave_i_frame_msssim": 0.971811, + "ave_i_frame_psnr_y": 33.525073, + "ave_i_frame_psnr_u": 36.738930, + "ave_i_frame_psnr_v": 38.633019, + "ave_i_frame_msssim_y": 0.972237, + "ave_i_frame_msssim_u": 0.966470, + "ave_i_frame_msssim_v": 0.974598, + "test_time": 36744.717673, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.068348, + "ave_all_frame_psnr": 34.565298, + "ave_all_frame_msssim": 0.971811, + "ave_all_frame_psnr_y": 33.525073, + "ave_all_frame_psnr_u": 36.738930, + "ave_all_frame_psnr_v": 38.633019, + "ave_all_frame_msssim_y": 0.972237, + "ave_all_frame_msssim_u": 0.966470, + "ave_all_frame_msssim_v": 0.974598, + "qp": 31, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "034": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.043653, + "ave_i_frame_psnr": 33.092429, + "ave_i_frame_msssim": 0.958954, + "ave_i_frame_psnr_y": 31.900932, + "ave_i_frame_psnr_u": 35.751630, + "ave_i_frame_psnr_v": 37.582208, + "ave_i_frame_msssim_y": 0.958002, + "ave_i_frame_msssim_u": 0.956139, + "ave_i_frame_msssim_v": 0.967483, + "test_time": 26955.753032, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.043653, + "ave_all_frame_psnr": 33.092429, + "ave_all_frame_msssim": 0.958954, + "ave_all_frame_psnr_y": 31.900932, + "ave_all_frame_psnr_u": 35.751630, + "ave_all_frame_psnr_v": 37.582208, + "ave_all_frame_msssim_y": 0.958002, + "ave_all_frame_msssim_u": 0.956139, + "ave_all_frame_msssim_v": 0.967483, + "qp": 34, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "037": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.027644, + "ave_i_frame_psnr": 31.749426, + "ave_i_frame_msssim": 0.941144, + "ave_i_frame_psnr_y": 30.321433, + "ave_i_frame_psnr_u": 35.174338, + "ave_i_frame_psnr_v": 36.892474, + "ave_i_frame_msssim_y": 0.936223, + "ave_i_frame_msssim_u": 0.950118, + "ave_i_frame_msssim_v": 0.961691, + "test_time": 21428.306087, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.027644, + "ave_all_frame_psnr": 31.749426, + "ave_all_frame_msssim": 0.941144, + "ave_all_frame_psnr_y": 30.321433, + "ave_all_frame_psnr_u": 35.174338, + "ave_all_frame_psnr_v": 36.892474, + "ave_all_frame_msssim_y": 0.936223, + "ave_all_frame_msssim_u": 0.950118, + "ave_all_frame_msssim_v": 0.961691, + "qp": 37, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "040": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.016993, + "ave_i_frame_psnr": 30.374441, + "ave_i_frame_msssim": 0.913865, + "ave_i_frame_psnr_y": 28.791012, + "ave_i_frame_psnr_u": 34.324951, + "ave_i_frame_psnr_v": 35.924507, + "ave_i_frame_msssim_y": 0.903000, + "ave_i_frame_msssim_u": 0.939886, + "ave_i_frame_msssim_v": 0.953034, + "test_time": 16398.528281, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.016993, + "ave_all_frame_psnr": 30.374441, + "ave_all_frame_msssim": 0.913865, + "ave_all_frame_psnr_y": 28.791012, + "ave_all_frame_psnr_u": 34.324951, + "ave_all_frame_psnr_v": 35.924507, + "ave_all_frame_msssim_y": 0.903000, + "ave_all_frame_msssim_u": 0.939886, + "ave_all_frame_msssim_v": 0.953034, + "qp": 40, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "043": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.010421, + "ave_i_frame_psnr": 29.129369, + "ave_i_frame_msssim": 0.878012, + "ave_i_frame_psnr_y": 27.427152, + "ave_i_frame_psnr_u": 33.495478, + "ave_i_frame_psnr_v": 34.976561, + "ave_i_frame_msssim_y": 0.858935, + "ave_i_frame_msssim_u": 0.927915, + "ave_i_frame_msssim_v": 0.942575, + "test_time": 12056.714354, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.010421, + "ave_all_frame_psnr": 29.129369, + "ave_all_frame_msssim": 0.878012, + "ave_all_frame_psnr_y": 27.427152, + "ave_all_frame_psnr_u": 33.495478, + "ave_all_frame_psnr_v": 34.976561, + "ave_all_frame_msssim_y": 0.858935, + "ave_all_frame_msssim_u": 0.927915, + "ave_all_frame_msssim_v": 0.942575, + "qp": 43, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "046": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006579, + "ave_i_frame_psnr": 27.962048, + "ave_i_frame_msssim": 0.843127, + "ave_i_frame_psnr_y": 26.278109, + "ave_i_frame_psnr_u": 32.376944, + "ave_i_frame_psnr_v": 33.650788, + "ave_i_frame_msssim_y": 0.818929, + "ave_i_frame_msssim_u": 0.907531, + "ave_i_frame_msssim_v": 0.923908, + "test_time": 8595.894438, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006579, + "ave_all_frame_psnr": 27.962048, + "ave_all_frame_msssim": 0.843127, + "ave_all_frame_psnr_y": 26.278109, + "ave_all_frame_psnr_u": 32.376944, + "ave_all_frame_psnr_v": 33.650788, + "ave_all_frame_msssim_y": 0.818929, + "ave_all_frame_msssim_u": 0.907531, + "ave_all_frame_msssim_v": 0.923908, + "qp": 46, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + }, + "049": { + "frame_pixel_num": 399360, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004187, + "ave_i_frame_psnr": 26.774718, + "ave_i_frame_msssim": 0.805625, + "ave_i_frame_psnr_y": 25.142004, + "ave_i_frame_psnr_u": 31.150913, + "ave_i_frame_psnr_v": 32.194806, + "ave_i_frame_msssim_y": 0.778607, + "ave_i_frame_msssim_u": 0.877978, + "ave_i_frame_msssim_v": 0.895381, + "test_time": 6306.863294, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004187, + "ave_all_frame_psnr": 26.774718, + "ave_all_frame_msssim": 0.805625, + "ave_all_frame_psnr_y": 25.142004, + "ave_all_frame_psnr_u": 31.150913, + "ave_all_frame_psnr_v": 32.194806, + "ave_all_frame_msssim_y": 0.778607, + "ave_all_frame_msssim_u": 0.877978, + "ave_all_frame_msssim_v": 0.895381, + "qp": 49, + "ds_name": "HEVC_C", + "seq_name": "RaceHorses_832x480_30.yuv" + } + } + }, + "HEVC_D": { + "BasketballPass_416x240_50.yuv": { + "022": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.271084, + "ave_i_frame_psnr": 41.579519, + "ave_i_frame_msssim": 0.994900, + "ave_i_frame_psnr_y": 41.075044, + "ave_i_frame_psnr_u": 43.463829, + "ave_i_frame_psnr_v": 42.722061, + "ave_i_frame_msssim_y": 0.995395, + "ave_i_frame_msssim_u": 0.992365, + "ave_i_frame_msssim_v": 0.994468, + "test_time": 21510.494120, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.271084, + "ave_all_frame_psnr": 41.579519, + "ave_all_frame_msssim": 0.994900, + "ave_all_frame_psnr_y": 41.075044, + "ave_all_frame_psnr_u": 43.463829, + "ave_all_frame_psnr_v": 42.722061, + "ave_all_frame_msssim_y": 0.995395, + "ave_all_frame_msssim_u": 0.992365, + "ave_all_frame_msssim_v": 0.994468, + "qp": 22, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "025": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.172652, + "ave_i_frame_psnr": 39.273492, + "ave_i_frame_msssim": 0.991287, + "ave_i_frame_psnr_y": 38.632077, + "ave_i_frame_psnr_u": 41.762868, + "ave_i_frame_psnr_v": 40.632609, + "ave_i_frame_msssim_y": 0.991897, + "ave_i_frame_msssim_u": 0.987825, + "ave_i_frame_msssim_v": 0.991092, + "test_time": 18632.701389, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.172652, + "ave_all_frame_psnr": 39.273492, + "ave_all_frame_msssim": 0.991287, + "ave_all_frame_psnr_y": 38.632077, + "ave_all_frame_psnr_u": 41.762868, + "ave_all_frame_psnr_v": 40.632609, + "ave_all_frame_msssim_y": 0.991897, + "ave_all_frame_msssim_u": 0.987825, + "ave_all_frame_msssim_v": 0.991092, + "qp": 25, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "028": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.107367, + "ave_i_frame_psnr": 37.072875, + "ave_i_frame_msssim": 0.985266, + "ave_i_frame_psnr_y": 36.263579, + "ave_i_frame_psnr_u": 40.205297, + "ave_i_frame_psnr_v": 38.796232, + "ave_i_frame_msssim_y": 0.985825, + "ave_i_frame_msssim_u": 0.981251, + "ave_i_frame_msssim_v": 0.985930, + "test_time": 15873.329253, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.107367, + "ave_all_frame_psnr": 37.072875, + "ave_all_frame_msssim": 0.985266, + "ave_all_frame_psnr_y": 36.263579, + "ave_all_frame_psnr_u": 40.205297, + "ave_all_frame_psnr_v": 38.796232, + "ave_all_frame_msssim_y": 0.985825, + "ave_all_frame_msssim_u": 0.981251, + "ave_all_frame_msssim_v": 0.985930, + "qp": 28, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "031": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.067000, + "ave_i_frame_psnr": 35.098993, + "ave_i_frame_msssim": 0.976298, + "ave_i_frame_psnr_y": 34.050196, + "ave_i_frame_psnr_u": 38.991049, + "ave_i_frame_psnr_v": 37.499724, + "ave_i_frame_msssim_y": 0.975918, + "ave_i_frame_msssim_u": 0.973953, + "ave_i_frame_msssim_v": 0.980918, + "test_time": 13879.858457, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.067000, + "ave_all_frame_psnr": 35.098993, + "ave_all_frame_msssim": 0.976298, + "ave_all_frame_psnr_y": 34.050196, + "ave_all_frame_psnr_u": 38.991049, + "ave_all_frame_psnr_v": 37.499724, + "ave_all_frame_msssim_y": 0.975918, + "ave_all_frame_msssim_u": 0.973953, + "ave_all_frame_msssim_v": 0.980918, + "qp": 31, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "034": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.044834, + "ave_i_frame_psnr": 33.471395, + "ave_i_frame_msssim": 0.964034, + "ave_i_frame_psnr_y": 32.313780, + "ave_i_frame_psnr_u": 37.734764, + "ave_i_frame_psnr_v": 36.153718, + "ave_i_frame_msssim_y": 0.962806, + "ave_i_frame_msssim_u": 0.962774, + "ave_i_frame_msssim_v": 0.972660, + "test_time": 10957.925470, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.044834, + "ave_all_frame_psnr": 33.471395, + "ave_all_frame_msssim": 0.964034, + "ave_all_frame_psnr_y": 32.313780, + "ave_all_frame_psnr_u": 37.734764, + "ave_all_frame_psnr_v": 36.153718, + "ave_all_frame_msssim_y": 0.962806, + "ave_all_frame_msssim_u": 0.962774, + "ave_all_frame_msssim_v": 0.972660, + "qp": 34, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "037": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.030195, + "ave_i_frame_psnr": 32.043418, + "ave_i_frame_msssim": 0.948610, + "ave_i_frame_psnr_y": 30.659665, + "ave_i_frame_psnr_u": 37.054674, + "ave_i_frame_psnr_v": 35.334679, + "ave_i_frame_msssim_y": 0.944217, + "ave_i_frame_msssim_u": 0.955984, + "ave_i_frame_msssim_v": 0.967590, + "test_time": 8362.739881, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.030195, + "ave_all_frame_psnr": 32.043418, + "ave_all_frame_msssim": 0.948610, + "ave_all_frame_psnr_y": 30.659665, + "ave_all_frame_psnr_u": 37.054674, + "ave_all_frame_psnr_v": 35.334679, + "ave_all_frame_msssim_y": 0.944217, + "ave_all_frame_msssim_u": 0.955984, + "ave_all_frame_msssim_v": 0.967590, + "qp": 37, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "040": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.019905, + "ave_i_frame_psnr": 30.574298, + "ave_i_frame_msssim": 0.926764, + "ave_i_frame_psnr_y": 29.082687, + "ave_i_frame_psnr_u": 36.029007, + "ave_i_frame_psnr_v": 34.069253, + "ave_i_frame_msssim_y": 0.919676, + "ave_i_frame_msssim_u": 0.940894, + "ave_i_frame_msssim_v": 0.955159, + "test_time": 6381.956493, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.019905, + "ave_all_frame_psnr": 30.574298, + "ave_all_frame_msssim": 0.926764, + "ave_all_frame_psnr_y": 29.082687, + "ave_all_frame_psnr_u": 36.029007, + "ave_all_frame_psnr_v": 34.069253, + "ave_all_frame_msssim_y": 0.919676, + "ave_all_frame_msssim_u": 0.940894, + "ave_all_frame_msssim_v": 0.955159, + "qp": 40, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "043": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013151, + "ave_i_frame_psnr": 29.155706, + "ave_i_frame_msssim": 0.899647, + "ave_i_frame_psnr_y": 27.549804, + "ave_i_frame_psnr_u": 35.103920, + "ave_i_frame_psnr_v": 32.842903, + "ave_i_frame_msssim_y": 0.888637, + "ave_i_frame_msssim_u": 0.925522, + "ave_i_frame_msssim_v": 0.939834, + "test_time": 4554.094124, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013151, + "ave_all_frame_psnr": 29.155706, + "ave_all_frame_msssim": 0.899647, + "ave_all_frame_psnr_y": 27.549804, + "ave_all_frame_psnr_u": 35.103920, + "ave_all_frame_psnr_v": 32.842903, + "ave_all_frame_msssim_y": 0.888637, + "ave_all_frame_msssim_u": 0.925522, + "ave_all_frame_msssim_v": 0.939834, + "qp": 43, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "046": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008566, + "ave_i_frame_psnr": 27.738428, + "ave_i_frame_msssim": 0.864237, + "ave_i_frame_psnr_y": 26.114329, + "ave_i_frame_psnr_u": 33.862739, + "ave_i_frame_psnr_v": 31.358708, + "ave_i_frame_msssim_y": 0.851012, + "ave_i_frame_msssim_u": 0.894958, + "ave_i_frame_msssim_v": 0.912866, + "test_time": 3301.087064, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008566, + "ave_all_frame_psnr": 27.738428, + "ave_all_frame_msssim": 0.864237, + "ave_all_frame_psnr_y": 26.114329, + "ave_all_frame_psnr_u": 33.862739, + "ave_all_frame_psnr_v": 31.358708, + "ave_all_frame_msssim_y": 0.851012, + "ave_all_frame_msssim_u": 0.894958, + "ave_all_frame_msssim_v": 0.912866, + "qp": 46, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + }, + "049": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005642, + "ave_i_frame_psnr": 26.317852, + "ave_i_frame_msssim": 0.815109, + "ave_i_frame_psnr_y": 24.683295, + "ave_i_frame_psnr_u": 32.597762, + "ave_i_frame_psnr_v": 29.845285, + "ave_i_frame_msssim_y": 0.798618, + "ave_i_frame_msssim_u": 0.854634, + "ave_i_frame_msssim_v": 0.874531, + "test_time": 2478.748799, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005642, + "ave_all_frame_psnr": 26.317852, + "ave_all_frame_msssim": 0.815109, + "ave_all_frame_psnr_y": 24.683295, + "ave_all_frame_psnr_u": 32.597762, + "ave_all_frame_psnr_v": 29.845285, + "ave_all_frame_msssim_y": 0.798618, + "ave_all_frame_msssim_u": 0.854634, + "ave_all_frame_msssim_v": 0.874531, + "qp": 49, + "ds_name": "HEVC_D", + "seq_name": "BasketballPass_416x240_50.yuv" + } + }, + "BlowingBubbles_416x240_50.yuv": { + "022": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.300652, + "ave_i_frame_psnr": 38.715173, + "ave_i_frame_msssim": 0.994484, + "ave_i_frame_psnr_y": 38.030147, + "ave_i_frame_psnr_u": 40.395990, + "ave_i_frame_psnr_v": 41.144507, + "ave_i_frame_msssim_y": 0.995876, + "ave_i_frame_msssim_u": 0.989503, + "ave_i_frame_msssim_v": 0.991108, + "test_time": 22553.737204, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.300652, + "ave_all_frame_psnr": 38.715173, + "ave_all_frame_msssim": 0.994484, + "ave_all_frame_psnr_y": 38.030147, + "ave_all_frame_psnr_u": 40.395990, + "ave_all_frame_psnr_v": 41.144507, + "ave_all_frame_msssim_y": 0.995876, + "ave_all_frame_msssim_u": 0.989503, + "ave_all_frame_msssim_v": 0.991108, + "qp": 22, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "025": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.172161, + "ave_i_frame_psnr": 36.552301, + "ave_i_frame_msssim": 0.990951, + "ave_i_frame_psnr_y": 35.693133, + "ave_i_frame_psnr_u": 38.845471, + "ave_i_frame_psnr_v": 39.414141, + "ave_i_frame_msssim_y": 0.993003, + "ave_i_frame_msssim_u": 0.983942, + "ave_i_frame_msssim_v": 0.985649, + "test_time": 18766.184671, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.172161, + "ave_all_frame_psnr": 36.552301, + "ave_all_frame_msssim": 0.990951, + "ave_all_frame_psnr_y": 35.693133, + "ave_all_frame_psnr_u": 38.845471, + "ave_all_frame_psnr_v": 39.414141, + "ave_all_frame_msssim_y": 0.993003, + "ave_all_frame_msssim_u": 0.983942, + "ave_all_frame_msssim_v": 0.985649, + "qp": 25, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "028": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.101663, + "ave_i_frame_psnr": 34.565379, + "ave_i_frame_msssim": 0.985435, + "ave_i_frame_psnr_y": 33.555892, + "ave_i_frame_psnr_u": 37.325307, + "ave_i_frame_psnr_v": 37.862372, + "ave_i_frame_msssim_y": 0.988337, + "ave_i_frame_msssim_u": 0.975405, + "ave_i_frame_msssim_v": 0.978049, + "test_time": 15370.598379, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.101663, + "ave_all_frame_psnr": 34.565379, + "ave_all_frame_msssim": 0.985435, + "ave_all_frame_psnr_y": 33.555892, + "ave_all_frame_psnr_u": 37.325307, + "ave_all_frame_psnr_v": 37.862372, + "ave_all_frame_msssim_y": 0.988337, + "ave_all_frame_msssim_u": 0.975405, + "ave_all_frame_msssim_v": 0.978049, + "qp": 28, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "031": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.059994, + "ave_i_frame_psnr": 32.715989, + "ave_i_frame_msssim": 0.976992, + "ave_i_frame_psnr_y": 31.534152, + "ave_i_frame_psnr_u": 36.017922, + "ave_i_frame_psnr_v": 36.505080, + "ave_i_frame_msssim_y": 0.980743, + "ave_i_frame_msssim_u": 0.964287, + "ave_i_frame_msssim_v": 0.967194, + "test_time": 11268.845172, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.059994, + "ave_all_frame_psnr": 32.715989, + "ave_all_frame_msssim": 0.976992, + "ave_all_frame_psnr_y": 31.534152, + "ave_all_frame_psnr_u": 36.017922, + "ave_all_frame_psnr_v": 36.505080, + "ave_all_frame_msssim_y": 0.980743, + "ave_all_frame_msssim_u": 0.964287, + "ave_all_frame_msssim_v": 0.967194, + "qp": 31, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "034": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.036680, + "ave_i_frame_psnr": 31.036347, + "ave_i_frame_msssim": 0.964258, + "ave_i_frame_psnr_y": 29.732744, + "ave_i_frame_psnr_u": 34.679106, + "ave_i_frame_psnr_v": 35.215207, + "ave_i_frame_msssim_y": 0.968890, + "ave_i_frame_msssim_u": 0.948367, + "ave_i_frame_msssim_v": 0.952359, + "test_time": 8258.474975, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.036680, + "ave_all_frame_psnr": 31.036347, + "ave_all_frame_msssim": 0.964258, + "ave_all_frame_psnr_y": 29.732744, + "ave_all_frame_psnr_u": 34.679106, + "ave_all_frame_psnr_v": 35.215207, + "ave_all_frame_msssim_y": 0.968890, + "ave_all_frame_msssim_u": 0.948367, + "ave_all_frame_msssim_v": 0.952359, + "qp": 34, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "037": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022449, + "ave_i_frame_psnr": 29.654347, + "ave_i_frame_msssim": 0.948928, + "ave_i_frame_psnr_y": 28.059642, + "ave_i_frame_psnr_u": 34.141733, + "ave_i_frame_psnr_v": 34.735194, + "ave_i_frame_msssim_y": 0.951247, + "ave_i_frame_msssim_u": 0.938845, + "ave_i_frame_msssim_v": 0.945096, + "test_time": 6636.657837, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022449, + "ave_all_frame_psnr": 29.654347, + "ave_all_frame_msssim": 0.948928, + "ave_all_frame_psnr_y": 28.059642, + "ave_all_frame_psnr_u": 34.141733, + "ave_all_frame_psnr_v": 34.735194, + "ave_all_frame_msssim_y": 0.951247, + "ave_all_frame_msssim_u": 0.938845, + "ave_all_frame_msssim_v": 0.945096, + "qp": 37, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "040": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013452, + "ave_i_frame_psnr": 28.301279, + "ave_i_frame_msssim": 0.925887, + "ave_i_frame_psnr_y": 26.535592, + "ave_i_frame_psnr_u": 33.295227, + "ave_i_frame_psnr_v": 33.901456, + "ave_i_frame_msssim_y": 0.925632, + "ave_i_frame_msssim_u": 0.922222, + "ave_i_frame_msssim_v": 0.931086, + "test_time": 5171.652444, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013452, + "ave_all_frame_psnr": 28.301279, + "ave_all_frame_msssim": 0.925887, + "ave_all_frame_psnr_y": 26.535592, + "ave_all_frame_psnr_u": 33.295227, + "ave_all_frame_psnr_v": 33.901456, + "ave_all_frame_msssim_y": 0.925632, + "ave_all_frame_msssim_u": 0.922222, + "ave_all_frame_msssim_v": 0.931086, + "qp": 40, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "043": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008181, + "ave_i_frame_psnr": 27.038274, + "ave_i_frame_msssim": 0.894051, + "ave_i_frame_psnr_y": 25.124031, + "ave_i_frame_psnr_u": 32.485848, + "ave_i_frame_psnr_v": 33.076159, + "ave_i_frame_msssim_y": 0.889449, + "ave_i_frame_msssim_u": 0.902272, + "ave_i_frame_msssim_v": 0.913438, + "test_time": 3775.786883, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008181, + "ave_all_frame_psnr": 27.038274, + "ave_all_frame_msssim": 0.894051, + "ave_all_frame_psnr_y": 25.124031, + "ave_all_frame_psnr_u": 32.485848, + "ave_all_frame_psnr_v": 33.076159, + "ave_all_frame_msssim_y": 0.889449, + "ave_all_frame_msssim_u": 0.902272, + "ave_all_frame_msssim_v": 0.913438, + "qp": 43, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "046": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005092, + "ave_i_frame_psnr": 25.793211, + "ave_i_frame_msssim": 0.847103, + "ave_i_frame_psnr_y": 23.835005, + "ave_i_frame_psnr_u": 31.304257, + "ave_i_frame_psnr_v": 32.031402, + "ave_i_frame_msssim_y": 0.835927, + "ave_i_frame_msssim_u": 0.869506, + "ave_i_frame_msssim_v": 0.891755, + "test_time": 2746.872026, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005092, + "ave_all_frame_psnr": 25.793211, + "ave_all_frame_msssim": 0.847103, + "ave_all_frame_psnr_y": 23.835005, + "ave_all_frame_psnr_u": 31.304257, + "ave_all_frame_psnr_v": 32.031402, + "ave_all_frame_msssim_y": 0.835927, + "ave_all_frame_msssim_u": 0.869506, + "ave_all_frame_msssim_v": 0.891755, + "qp": 46, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + }, + "049": { + "frame_pixel_num": 99840, + "i_frame_num": 500, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003371, + "ave_i_frame_psnr": 24.649341, + "ave_i_frame_msssim": 0.789922, + "ave_i_frame_psnr_y": 22.729576, + "ave_i_frame_psnr_u": 30.047653, + "ave_i_frame_psnr_v": 30.769614, + "ave_i_frame_msssim_y": 0.774213, + "ave_i_frame_msssim_u": 0.824815, + "ave_i_frame_msssim_v": 0.849285, + "test_time": 2054.751692, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003371, + "ave_all_frame_psnr": 24.649341, + "ave_all_frame_msssim": 0.789922, + "ave_all_frame_psnr_y": 22.729576, + "ave_all_frame_psnr_u": 30.047653, + "ave_all_frame_psnr_v": 30.769614, + "ave_all_frame_msssim_y": 0.774213, + "ave_all_frame_msssim_u": 0.824815, + "ave_all_frame_msssim_v": 0.849285, + "qp": 49, + "ds_name": "HEVC_D", + "seq_name": "BlowingBubbles_416x240_50.yuv" + } + }, + "BQSquare_416x240_60.yuv": { + "022": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.258646, + "ave_i_frame_psnr": 39.404213, + "ave_i_frame_msssim": 0.994177, + "ave_i_frame_psnr_y": 38.166038, + "ave_i_frame_psnr_u": 42.545982, + "ave_i_frame_psnr_v": 43.691495, + "ave_i_frame_msssim_y": 0.994997, + "ave_i_frame_msssim_u": 0.990345, + "ave_i_frame_msssim_v": 0.993092, + "test_time": 24299.148543, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.258646, + "ave_all_frame_psnr": 39.404213, + "ave_all_frame_msssim": 0.994177, + "ave_all_frame_psnr_y": 38.166038, + "ave_all_frame_psnr_u": 42.545982, + "ave_all_frame_psnr_v": 43.691495, + "ave_all_frame_msssim_y": 0.994997, + "ave_all_frame_msssim_u": 0.990345, + "ave_all_frame_msssim_v": 0.993092, + "qp": 22, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "025": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.125329, + "ave_i_frame_psnr": 37.376329, + "ave_i_frame_msssim": 0.990873, + "ave_i_frame_psnr_y": 35.806134, + "ave_i_frame_psnr_u": 41.517837, + "ave_i_frame_psnr_v": 42.655988, + "ave_i_frame_msssim_y": 0.991566, + "ave_i_frame_msssim_u": 0.986671, + "ave_i_frame_msssim_v": 0.990918, + "test_time": 19960.646071, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.125329, + "ave_all_frame_psnr": 37.376329, + "ave_all_frame_msssim": 0.990873, + "ave_all_frame_psnr_y": 35.806134, + "ave_all_frame_psnr_u": 41.517837, + "ave_all_frame_psnr_v": 42.655988, + "ave_all_frame_msssim_y": 0.991566, + "ave_all_frame_msssim_u": 0.986671, + "ave_all_frame_msssim_v": 0.990918, + "qp": 25, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "028": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.065971, + "ave_i_frame_psnr": 35.603039, + "ave_i_frame_msssim": 0.986460, + "ave_i_frame_psnr_y": 33.789602, + "ave_i_frame_psnr_u": 40.515028, + "ave_i_frame_psnr_v": 41.571670, + "ave_i_frame_msssim_y": 0.986969, + "ave_i_frame_msssim_u": 0.981918, + "ave_i_frame_msssim_v": 0.987943, + "test_time": 16045.796822, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.065971, + "ave_all_frame_psnr": 35.603039, + "ave_all_frame_msssim": 0.986460, + "ave_all_frame_psnr_y": 33.789602, + "ave_all_frame_psnr_u": 40.515028, + "ave_all_frame_psnr_v": 41.571670, + "ave_all_frame_msssim_y": 0.986969, + "ave_all_frame_msssim_u": 0.981918, + "ave_all_frame_msssim_v": 0.987943, + "qp": 28, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "031": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.036227, + "ave_i_frame_psnr": 33.920543, + "ave_i_frame_msssim": 0.980254, + "ave_i_frame_psnr_y": 31.907851, + "ave_i_frame_psnr_u": 39.491668, + "ave_i_frame_psnr_v": 40.425565, + "ave_i_frame_msssim_y": 0.980673, + "ave_i_frame_msssim_u": 0.974771, + "ave_i_frame_msssim_v": 0.983223, + "test_time": 11851.325558, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.036227, + "ave_all_frame_psnr": 33.920543, + "ave_all_frame_msssim": 0.980254, + "ave_all_frame_psnr_y": 31.907851, + "ave_all_frame_psnr_u": 39.491668, + "ave_all_frame_psnr_v": 40.425565, + "ave_all_frame_msssim_y": 0.980673, + "ave_all_frame_msssim_u": 0.974771, + "ave_all_frame_msssim_v": 0.983223, + "qp": 31, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "034": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.022249, + "ave_i_frame_psnr": 32.407897, + "ave_i_frame_msssim": 0.973123, + "ave_i_frame_psnr_y": 30.248662, + "ave_i_frame_psnr_u": 38.548843, + "ave_i_frame_psnr_v": 39.222365, + "ave_i_frame_msssim_y": 0.973553, + "ave_i_frame_msssim_u": 0.966178, + "ave_i_frame_msssim_v": 0.977491, + "test_time": 8684.784597, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.022249, + "ave_all_frame_psnr": 32.407897, + "ave_all_frame_msssim": 0.973123, + "ave_all_frame_psnr_y": 30.248662, + "ave_all_frame_psnr_u": 38.548843, + "ave_all_frame_psnr_v": 39.222365, + "ave_all_frame_msssim_y": 0.973553, + "ave_all_frame_msssim_u": 0.966178, + "ave_all_frame_msssim_v": 0.977491, + "qp": 34, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "037": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.014030, + "ave_i_frame_psnr": 31.051991, + "ave_i_frame_msssim": 0.966279, + "ave_i_frame_psnr_y": 28.614762, + "ave_i_frame_psnr_u": 37.964828, + "ave_i_frame_psnr_v": 38.762526, + "ave_i_frame_msssim_y": 0.966145, + "ave_i_frame_msssim_u": 0.959850, + "ave_i_frame_msssim_v": 0.973516, + "test_time": 6267.457376, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.014030, + "ave_all_frame_psnr": 31.051991, + "ave_all_frame_msssim": 0.966279, + "ave_all_frame_psnr_y": 28.614762, + "ave_all_frame_psnr_u": 37.964828, + "ave_all_frame_psnr_v": 38.762526, + "ave_all_frame_msssim_y": 0.966145, + "ave_all_frame_msssim_u": 0.959850, + "ave_all_frame_msssim_v": 0.973516, + "qp": 37, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "040": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.008966, + "ave_i_frame_psnr": 29.644962, + "ave_i_frame_msssim": 0.957017, + "ave_i_frame_psnr_y": 26.948158, + "ave_i_frame_psnr_u": 37.343105, + "ave_i_frame_psnr_v": 38.127648, + "ave_i_frame_msssim_y": 0.955968, + "ave_i_frame_msssim_u": 0.950987, + "ave_i_frame_msssim_v": 0.969339, + "test_time": 4472.454009, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.008966, + "ave_all_frame_psnr": 29.644962, + "ave_all_frame_msssim": 0.957017, + "ave_all_frame_psnr_y": 26.948158, + "ave_all_frame_psnr_u": 37.343105, + "ave_all_frame_psnr_v": 38.127648, + "ave_all_frame_msssim_y": 0.955968, + "ave_all_frame_msssim_u": 0.950987, + "ave_all_frame_msssim_v": 0.969339, + "qp": 40, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "043": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.005986, + "ave_i_frame_psnr": 28.281653, + "ave_i_frame_msssim": 0.945875, + "ave_i_frame_psnr_y": 25.268982, + "ave_i_frame_psnr_u": 37.070810, + "ave_i_frame_psnr_v": 37.568518, + "ave_i_frame_msssim_y": 0.942857, + "ave_i_frame_msssim_u": 0.945278, + "ave_i_frame_msssim_v": 0.964581, + "test_time": 3617.084887, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.005986, + "ave_all_frame_psnr": 28.281653, + "ave_all_frame_msssim": 0.945875, + "ave_all_frame_psnr_y": 25.268982, + "ave_all_frame_psnr_u": 37.070810, + "ave_all_frame_psnr_v": 37.568518, + "ave_all_frame_msssim_y": 0.942857, + "ave_all_frame_msssim_u": 0.945278, + "ave_all_frame_msssim_v": 0.964581, + "qp": 43, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "046": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.004127, + "ave_i_frame_psnr": 26.854486, + "ave_i_frame_msssim": 0.930159, + "ave_i_frame_psnr_y": 23.688602, + "ave_i_frame_psnr_u": 36.318881, + "ave_i_frame_psnr_v": 36.385393, + "ave_i_frame_msssim_y": 0.924732, + "ave_i_frame_msssim_u": 0.938170, + "ave_i_frame_msssim_v": 0.954708, + "test_time": 2812.480960, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.004127, + "ave_all_frame_psnr": 26.854486, + "ave_all_frame_msssim": 0.930159, + "ave_all_frame_psnr_y": 23.688602, + "ave_all_frame_psnr_u": 36.318881, + "ave_all_frame_psnr_v": 36.385393, + "ave_all_frame_msssim_y": 0.924732, + "ave_all_frame_msssim_u": 0.938170, + "ave_all_frame_msssim_v": 0.954708, + "qp": 46, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + }, + "049": { + "frame_pixel_num": 99840, + "i_frame_num": 600, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.003083, + "ave_i_frame_psnr": 25.441266, + "ave_i_frame_msssim": 0.906606, + "ave_i_frame_psnr_y": 22.179904, + "ave_i_frame_psnr_u": 35.352128, + "ave_i_frame_psnr_v": 35.098571, + "ave_i_frame_msssim_y": 0.898620, + "ave_i_frame_msssim_u": 0.921254, + "ave_i_frame_msssim_v": 0.939872, + "test_time": 2246.141007, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.003083, + "ave_all_frame_psnr": 25.441266, + "ave_all_frame_msssim": 0.906606, + "ave_all_frame_psnr_y": 22.179904, + "ave_all_frame_psnr_u": 35.352128, + "ave_all_frame_psnr_v": 35.098571, + "ave_all_frame_msssim_y": 0.898620, + "ave_all_frame_msssim_u": 0.921254, + "ave_all_frame_msssim_v": 0.939872, + "qp": 49, + "ds_name": "HEVC_D", + "seq_name": "BQSquare_416x240_60.yuv" + } + }, + "RaceHorses_416x240_30.yuv": { + "022": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.332116, + "ave_i_frame_psnr": 39.999494, + "ave_i_frame_msssim": 0.993028, + "ave_i_frame_psnr_y": 39.613411, + "ave_i_frame_psnr_u": 40.539559, + "ave_i_frame_psnr_v": 41.775930, + "ave_i_frame_msssim_y": 0.994238, + "ave_i_frame_msssim_u": 0.989166, + "ave_i_frame_msssim_v": 0.989632, + "test_time": 16118.046571, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.332116, + "ave_all_frame_psnr": 39.999494, + "ave_all_frame_msssim": 0.993028, + "ave_all_frame_psnr_y": 39.613411, + "ave_all_frame_psnr_u": 40.539559, + "ave_all_frame_psnr_v": 41.775930, + "ave_all_frame_msssim_y": 0.994238, + "ave_all_frame_msssim_u": 0.989166, + "ave_all_frame_msssim_v": 0.989632, + "qp": 22, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "025": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.206544, + "ave_i_frame_psnr": 37.663589, + "ave_i_frame_msssim": 0.988012, + "ave_i_frame_psnr_y": 37.081908, + "ave_i_frame_psnr_u": 38.775218, + "ave_i_frame_psnr_v": 40.042041, + "ave_i_frame_msssim_y": 0.989631, + "ave_i_frame_msssim_u": 0.982407, + "ave_i_frame_msssim_v": 0.983900, + "test_time": 13256.550250, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.206544, + "ave_all_frame_psnr": 37.663589, + "ave_all_frame_msssim": 0.988012, + "ave_all_frame_psnr_y": 37.081908, + "ave_all_frame_psnr_u": 38.775218, + "ave_all_frame_psnr_v": 40.042041, + "ave_all_frame_msssim_y": 0.989631, + "ave_all_frame_msssim_u": 0.982407, + "ave_all_frame_msssim_v": 0.983900, + "qp": 25, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "028": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.126641, + "ave_i_frame_psnr": 35.457111, + "ave_i_frame_msssim": 0.979483, + "ave_i_frame_psnr_y": 34.648451, + "ave_i_frame_psnr_u": 37.263380, + "ave_i_frame_psnr_v": 38.502804, + "ave_i_frame_msssim_y": 0.981034, + "ave_i_frame_msssim_u": 0.973393, + "ave_i_frame_msssim_v": 0.976268, + "test_time": 11022.721568, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.126641, + "ave_all_frame_psnr": 35.457111, + "ave_all_frame_msssim": 0.979483, + "ave_all_frame_psnr_y": 34.648451, + "ave_all_frame_psnr_u": 37.263380, + "ave_all_frame_psnr_v": 38.502804, + "ave_all_frame_msssim_y": 0.981034, + "ave_all_frame_msssim_u": 0.973393, + "ave_all_frame_msssim_v": 0.976268, + "qp": 28, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "031": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.077769, + "ave_i_frame_psnr": 33.510136, + "ave_i_frame_msssim": 0.966359, + "ave_i_frame_psnr_y": 32.438328, + "ave_i_frame_psnr_u": 36.152093, + "ave_i_frame_psnr_v": 37.299023, + "ave_i_frame_msssim_y": 0.966411, + "ave_i_frame_msssim_u": 0.964273, + "ave_i_frame_msssim_v": 0.968139, + "test_time": 9577.669104, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.077769, + "ave_all_frame_psnr": 33.510136, + "ave_all_frame_msssim": 0.966359, + "ave_all_frame_psnr_y": 32.438328, + "ave_all_frame_psnr_u": 36.152093, + "ave_all_frame_psnr_v": 37.299023, + "ave_all_frame_msssim_y": 0.966411, + "ave_all_frame_msssim_u": 0.964273, + "ave_all_frame_msssim_v": 0.968139, + "qp": 31, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "034": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.050119, + "ave_i_frame_psnr": 31.899884, + "ave_i_frame_msssim": 0.947777, + "ave_i_frame_psnr_y": 30.695261, + "ave_i_frame_psnr_u": 34.927638, + "ave_i_frame_psnr_v": 36.099874, + "ave_i_frame_msssim_y": 0.945826, + "ave_i_frame_msssim_u": 0.950593, + "ave_i_frame_msssim_v": 0.956666, + "test_time": 7209.029020, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.050119, + "ave_all_frame_psnr": 31.899884, + "ave_all_frame_msssim": 0.947777, + "ave_all_frame_psnr_y": 30.695261, + "ave_all_frame_psnr_u": 34.927638, + "ave_all_frame_psnr_v": 36.099874, + "ave_all_frame_msssim_y": 0.945826, + "ave_all_frame_msssim_u": 0.950593, + "ave_all_frame_msssim_v": 0.956666, + "qp": 34, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "037": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.032717, + "ave_i_frame_psnr": 30.568044, + "ave_i_frame_msssim": 0.924612, + "ave_i_frame_psnr_y": 29.139569, + "ave_i_frame_psnr_u": 34.284017, + "ave_i_frame_psnr_v": 35.422925, + "ave_i_frame_msssim_y": 0.917341, + "ave_i_frame_msssim_u": 0.943302, + "ave_i_frame_msssim_v": 0.949546, + "test_time": 5366.588482, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.032717, + "ave_all_frame_psnr": 30.568044, + "ave_all_frame_msssim": 0.924612, + "ave_all_frame_psnr_y": 29.139569, + "ave_all_frame_psnr_u": 34.284017, + "ave_all_frame_psnr_v": 35.422925, + "ave_all_frame_msssim_y": 0.917341, + "ave_all_frame_msssim_u": 0.943302, + "ave_all_frame_msssim_v": 0.949546, + "qp": 37, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "040": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.021267, + "ave_i_frame_psnr": 29.274540, + "ave_i_frame_msssim": 0.897362, + "ave_i_frame_psnr_y": 27.770388, + "ave_i_frame_psnr_u": 33.271388, + "ave_i_frame_psnr_v": 34.302604, + "ave_i_frame_msssim_y": 0.886216, + "ave_i_frame_msssim_u": 0.927885, + "ave_i_frame_msssim_v": 0.933708, + "test_time": 4071.237993, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.021267, + "ave_all_frame_psnr": 29.274540, + "ave_all_frame_msssim": 0.897362, + "ave_all_frame_psnr_y": 27.770388, + "ave_all_frame_psnr_u": 33.271388, + "ave_all_frame_psnr_v": 34.302604, + "ave_all_frame_msssim_y": 0.886216, + "ave_all_frame_msssim_u": 0.927885, + "ave_all_frame_msssim_v": 0.933708, + "qp": 40, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "043": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.013878, + "ave_i_frame_psnr": 28.018806, + "ave_i_frame_msssim": 0.865901, + "ave_i_frame_psnr_y": 26.437483, + "ave_i_frame_psnr_u": 32.252560, + "ave_i_frame_psnr_v": 33.272991, + "ave_i_frame_msssim_y": 0.850919, + "ave_i_frame_msssim_u": 0.906896, + "ave_i_frame_msssim_v": 0.914792, + "test_time": 3070.635436, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.013878, + "ave_all_frame_psnr": 28.018806, + "ave_all_frame_msssim": 0.865901, + "ave_all_frame_psnr_y": 26.437483, + "ave_all_frame_psnr_u": 32.252560, + "ave_all_frame_psnr_v": 33.272991, + "ave_all_frame_msssim_y": 0.850919, + "ave_all_frame_msssim_u": 0.906896, + "ave_all_frame_msssim_v": 0.914792, + "qp": 43, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "046": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.009067, + "ave_i_frame_psnr": 26.710246, + "ave_i_frame_msssim": 0.826273, + "ave_i_frame_psnr_y": 25.137961, + "ave_i_frame_psnr_u": 31.011019, + "ave_i_frame_psnr_v": 31.843184, + "ave_i_frame_msssim_y": 0.809875, + "ave_i_frame_msssim_u": 0.872501, + "ave_i_frame_msssim_v": 0.878439, + "test_time": 2229.453698, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.009067, + "ave_all_frame_psnr": 26.710246, + "ave_all_frame_msssim": 0.826273, + "ave_all_frame_psnr_y": 25.137961, + "ave_all_frame_psnr_u": 31.011019, + "ave_all_frame_psnr_v": 31.843184, + "ave_all_frame_msssim_y": 0.809875, + "ave_all_frame_msssim_u": 0.872501, + "ave_all_frame_msssim_v": 0.878439, + "qp": 46, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + }, + "049": { + "frame_pixel_num": 99840, + "i_frame_num": 300, + "p_frame_num": 0, + "ave_i_frame_bpp": 0.006039, + "ave_i_frame_psnr": 25.422969, + "ave_i_frame_msssim": 0.779890, + "ave_i_frame_psnr_y": 23.873765, + "ave_i_frame_psnr_u": 29.639492, + "ave_i_frame_psnr_v": 30.501676, + "ave_i_frame_msssim_y": 0.760906, + "ave_i_frame_msssim_u": 0.835136, + "ave_i_frame_msssim_v": 0.838550, + "test_time": 1612.489115, + "ave_p_frame_bpp": 0, + "ave_p_frame_psnr": 0, + "ave_p_frame_msssim": 0, + "ave_p_frame_psnr_y": 0, + "ave_p_frame_psnr_u": 0, + "ave_p_frame_psnr_v": 0, + "ave_p_frame_msssim_y": 0, + "ave_p_frame_msssim_u": 0, + "ave_p_frame_msssim_v": 0, + "ave_all_frame_bpp": 0.006039, + "ave_all_frame_psnr": 25.422969, + "ave_all_frame_msssim": 0.779890, + "ave_all_frame_psnr_y": 23.873765, + "ave_all_frame_psnr_u": 29.639492, + "ave_all_frame_psnr_v": 30.501676, + "ave_all_frame_msssim_y": 0.760906, + "ave_all_frame_msssim_u": 0.835136, + "ave_all_frame_msssim_v": 0.838550, + "qp": 49, + "ds_name": "HEVC_D", + "seq_name": "RaceHorses_416x240_30.yuv" + } + } + } +} \ No newline at end of file diff --git a/assets/bd_rate_speed.png b/assets/bd_rate_speed.png index 3773a1d..b829b4c 100644 Binary files a/assets/bd_rate_speed.png and b/assets/bd_rate_speed.png differ diff --git a/assets/complexity.png b/assets/complexity.png index 8bee325..6673db5 100644 Binary files a/assets/complexity.png and b/assets/complexity.png differ diff --git a/assets/intra_compare.png b/assets/intra_compare.png index b3cf9b1..cbde8ff 100644 Binary files a/assets/intra_compare.png and b/assets/intra_compare.png differ diff --git a/assets/practical_performance.png b/assets/practical_performance.png index 31675dc..c46877d 100644 Binary files a/assets/practical_performance.png and b/assets/practical_performance.png differ diff --git a/assets/rd_curve.png b/assets/rd_curve.png new file mode 100644 index 0000000..fe70374 Binary files /dev/null and b/assets/rd_curve.png differ diff --git a/checkpoints/.gitkeep b/checkpoints/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/compare_bd_rate.py b/compare_bd_rate.py new file mode 100644 index 0000000..918fb8f --- /dev/null +++ b/compare_bd_rate.py @@ -0,0 +1,417 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import argparse +import json +import matplotlib +import numpy as np +import os +import sys +import warnings + +from bd_metric.bjontegaard_metric import BD_RATE +from matplotlib import pyplot as plt + +from src.utils.common import create_folder + + +def _matplotlib_plt(data_dict, out_path, ds_name=None, distortion_metric='psnr'): + plt.figure() + for key in data_dict: + plt.plot(data_dict[key]['bpp'], data_dict[key][distortion_metric], label=key) + plt.scatter(data_dict[key]['bpp'], data_dict[key][distortion_metric]) + + if ds_name is not None: + plt.gca().set_title(ds_name) + plt.grid(True) + plt.legend(loc='lower right') + plt.xlim(left=0.0) + plt.savefig(out_path) + plt.close('all') + + +def avg_results(all_dataset_names, results): + all_bd_rates = {} + for method in sorted(results): + for ds_name in all_dataset_names: + if method not in all_bd_rates: + all_bd_rates[method] = [] + if ds_name in results[method]: + all_bd_rates[method].append(results[method][ds_name]) + avg_bd_rates = {} + for key, value in all_bd_rates.items(): + if len(value) > 0: + avg_bd_rates[key] = np.mean(value) + return avg_bd_rates + + +def flatten_test_results(res): + new_res = {} + for key_method in res: + new_res[key_method] = {} + for ds_name in res[key_method]: + for seq in res[key_method][ds_name]: + ds_seq_name = seq + new_res[key_method][ds_seq_name] = res[key_method][ds_name][seq] + return new_res + + +def matplotlib_plt(all_dataset_names, data_dict, out_prefix, + distortion_metric, plot_scheme='combined'): + subplot_dicts = [] + for ds_name in all_dataset_names: + ds_data_dict = {} + for key, value in data_dict.items(): + if ds_name in value: + ds_data_dict[key] = value[ds_name] + if plot_scheme == 'separate': + _matplotlib_plt(ds_data_dict, + f'{out_prefix}_{distortion_metric}_{ds_name}.png', + ds_name=ds_name, + distortion_metric=distortion_metric) + else: + subplot_dicts.append({'data_dict': ds_data_dict, 'ds_name': ds_name}) + + if plot_scheme == 'combined': + fig, axs = plt.subplots(1, len(subplot_dicts), figsize=(5*len(subplot_dicts), 4)) + if len(subplot_dicts) == 1: + axs = [axs] + for ax, d in zip(axs, subplot_dicts): + data_dict = d['data_dict'] + ds_name = d['ds_name'] + for k in data_dict: + ax.plot(data_dict[k]['bpp'], data_dict[k][distortion_metric], label=k) + ax.scatter(data_dict[k]['bpp'], data_dict[k][distortion_metric]) + + ax.grid(True) + ax.legend(loc='lower right') + ax.set_title(ds_name) + ax.set_xlim(left=0.0) + + fig.tight_layout() + fig.savefig(out_prefix+'_'+distortion_metric+'.png') + + +def mean_over_rate_point(rate_point, distortion_metric): + i_frame_num = 0 + p_frame_num = 0 + i_frame_bpp = 0.0 + i_frame_dist = 0.0 + p_frame_bpp = 0.0 + p_frame_dist = 0.0 + all_frame_bpp = 0.0 + all_frame_dist = 0.0 + i_frame_dist_key = f'ave_i_frame_{distortion_metric}' + p_frame_dist_key = f'ave_p_frame_{distortion_metric}' + all_frame_dist_key = f'ave_all_frame_{distortion_metric}' + for seq in rate_point: + if i_frame_dist_key not in seq: + seq[i_frame_dist_key] = 0 + if p_frame_dist_key not in seq: + seq[p_frame_dist_key] = 0 + if all_frame_dist_key not in seq: + seq[all_frame_dist_key] = 0 + + i_frame_num += seq['i_frame_num'] + p_frame_num += seq['p_frame_num'] + + i_frame_bpp += seq['ave_i_frame_bpp'] * seq['i_frame_num'] + i_frame_dist += seq[i_frame_dist_key] * seq['i_frame_num'] + + p_frame_bpp += seq['ave_p_frame_bpp'] * seq['p_frame_num'] + p_frame_dist += seq[p_frame_dist_key] * seq['p_frame_num'] + + all_frame_bpp += seq['ave_all_frame_bpp'] * (seq['p_frame_num'] + seq['i_frame_num']) + all_frame_dist += seq[all_frame_dist_key] * (seq['p_frame_num'] + seq['i_frame_num']) + + out_res = {} + out_res['i_frame_num'] = i_frame_num + out_res['p_frame_num'] = p_frame_num + + all_frame_num = i_frame_num + p_frame_num + i_frame_num = 1 if i_frame_num == 0 else i_frame_num + p_frame_num = 1 if p_frame_num == 0 else p_frame_num + + out_res['ave_i_frame_bpp'] = i_frame_bpp / i_frame_num + out_res[i_frame_dist_key] = i_frame_dist / i_frame_num + out_res['ave_p_frame_bpp'] = p_frame_bpp / p_frame_num + out_res[p_frame_dist_key] = p_frame_dist / p_frame_num + out_res['ave_all_frame_bpp'] = all_frame_bpp / all_frame_num + out_res[all_frame_dist_key] = all_frame_dist / all_frame_num + return out_res + + +def mean_over_sequence(res, distortion_metric): + new_res = {} # model -> dataset -> [models] + for m in res: + new_res[m] = {} + for d in res[m]: + rate_points = {} + for s in res[m][d]: + for rate_point, value in res[m][d][s].items(): + if rate_point in rate_points: + rate_points[rate_point].append(value) + else: + rate_points[rate_point] = [value] + new_res[m][d] = {} + for rate_point, value in rate_points.items(): + new_res[m][d][rate_point] = mean_over_rate_point(value, distortion_metric) + return new_res + + +def parse_args(argv): + parser = argparse.ArgumentParser() + + parser.add_argument('--compare_between', type=str, default='class', + choices=['class', 'sequence'], + help='compare the performance between different classes/sequences') + parser.add_argument('--compare_frame_type', type=str, default='default', + choices=['default', 'all'], + help='frame type to compare BD-Rate, default is i, p, and all') + parser.add_argument('--base_method', type=str, required=True, help='name of the anchor model') + parser.add_argument('--log_paths', type=str, required=True, nargs='+', + help='list of model test result paths, model name followed by file path') + parser.add_argument('--output_path', type=str, default='stdout', + help='print the results to console or save to file; TXT or CSV') + parser.add_argument('--plot_path', type=str, default='', help='path to save the plots') + parser.add_argument('--plot_scheme', type=str, default=None, + choices=[None, 'combined', 'separate'], help='RD curve plot scheme') + parser.add_argument('--distortion_metrics', type=str, nargs='+', default=['psnr'], + choices=['psnr', 'msssim', 'psnr_y', 'psnr_u', 'psnr_v', + 'msssim_y', 'msssim_u', 'msssim_v'], + help='distortion metrics used to calculate BD-Rate and plot') + parser.add_argument('--plot_rd_curve', type=int, default=1, choices=[0, 1], + help='if 1, plot RD curves') + parser.add_argument('--rate_exclude', type=str, required=False, nargs='+', + default=None, + help='list of rate points to be excluded') + + args = parser.parse_args(argv) + return args + + +def retrieve_data(json_dict, frame_type, base_method_name, distortion_metric): + data_dict = {} + results = {} + for key_method in json_dict: + data_dict[key_method] = {} + for ds_name in json_dict[key_method]: + data_dict[key_method][ds_name] = {} + data_dict[key_method][ds_name]['bpp'] = [] + data_dict[key_method][ds_name][distortion_metric] = [] + for _, one_data in json_dict[key_method][ds_name].items(): + data_dict[key_method][ds_name]['bpp'].append( + one_data[f'ave_{frame_type}_frame_bpp']) + data_dict[key_method][ds_name][distortion_metric].append( + one_data[f'ave_{frame_type}_frame_{distortion_metric}']) + + results[distortion_metric] = {} + for key_method in json_dict: + if key_method == base_method_name: + continue + results[distortion_metric][key_method] = {} + for ds_name in json_dict[key_method]: + if (ds_name in data_dict[base_method_name] + and len(data_dict[key_method][ds_name]['bpp']) >= 3 + and data_dict[base_method_name][ds_name]['bpp'][0] > 0 + and data_dict[key_method][ds_name][distortion_metric][0] is not None + and data_dict[key_method][ds_name][distortion_metric][0] > 0): + results[distortion_metric][key_method][ds_name] = BD_RATE( + data_dict[base_method_name][ds_name]['bpp'], + data_dict[base_method_name][ds_name][distortion_metric], + data_dict[key_method][ds_name]['bpp'], + data_dict[key_method][ds_name][distortion_metric], 1) + + return data_dict, results + + +def rotate_results(ds_names, results, print_overall=False): + new_ds_names = set() + new_results = {} + for ds in ds_names: + new_results[ds] = {} + for m in results: + if ds in results[m]: + new_results[ds][m] = results[m][ds] + new_ds_names.add(m) + if print_overall: + new_results['* Overall'] = {} + new_results['* Average'] = {} + for m in results: + if '* Overall' in results[m]: + new_results['* Overall'][m] = results[m]['* Overall'] + new_results['* Average'][m] = results[m]['* Average'] + return list(new_ds_names), new_results + + +def print_results(all_dataset_names, results, rotate=False, print_overall=False): + if len(results.keys()) == 0: + return + + if rotate: + # after rotation, the meaning of all_dataset_names and results are exchanged + all_dataset_names, results = rotate_results(all_dataset_names, results, print_overall) + + all_dataset_names = sorted([x for x in all_dataset_names if not x.startswith('*')]) + all_method_names = sorted([x for x in results.keys() if not x.startswith('*')]) + if print_overall and rotate: + all_method_names += ['* Overall', '* Average'] + elif print_overall: + all_dataset_names += ['* Overall', '* Average'] + method_name_l = max(len(x) for x in results.keys()) + 2 + + line = ' ' * method_name_l + for x in all_dataset_names: + line += f' {x:{len(x)+2}}' + print(line) + + for method in all_method_names: + line = f'{method:{method_name_l}}' + for ds_name in all_dataset_names: + if ds_name not in results[method]: + line += ' ' * (1 + len(ds_name)+2) + else: + line += f' {results[method][ds_name]:<{len(ds_name)+2}.1f}' + print(line) + + +def print_results_different_metric(all_dataset_names, all_sequence_names, seq_results, results): + for ds in sorted(all_dataset_names): + print('-'*4, ds, '-'*4) + print_seq_results = {} + avg_bd_rates = avg_results(all_sequence_names[ds], seq_results) + for m in sorted(list(results.keys())): + if ds in results[m]: + print_seq_results[m] = {} + for seq in all_sequence_names[ds]: + if seq in seq_results[m]: + print_seq_results[m][seq] = seq_results[m][seq] + print_seq_results[m]['* Overall'] = results[m][ds] + print_seq_results[m]['* Average'] = avg_bd_rates[m] + + print_results(all_sequence_names[ds], + print_seq_results, + rotate=True, + print_overall=True) + print() + + +def compare(json_dict, ds_seq_names, base_method_name, compare_between, plot_path, plot_scheme, + distortion_metric, plot_rd_curve, compare_frame_type): + cls_result_dict = mean_over_sequence(json_dict, distortion_metric) + all_dataset_names = sorted(list(ds_seq_names.keys())) + if compare_between == 'sequence': + seq_json_dict = flatten_test_results(json_dict) + all_sequence_names = {} + for key, value in ds_seq_names.items(): + all_sequence_names[key] = [] + for seq in value: + all_sequence_names[key].append(seq) + + if compare_frame_type == 'default': + frame_types = ['i', 'p', 'all'] + else: + frame_types = [compare_frame_type] + + for frame_type in frame_types: + print('='*12 + f'{frame_type:>3s} frame' + '='*12) + frame_data, results_list = retrieve_data(cls_result_dict, frame_type, + base_method_name, + distortion_metric) + if compare_between == 'sequence': + seq_frame_data, seq_results_list = retrieve_data( + seq_json_dict, + frame_type, + base_method_name, + distortion_metric) + + print_results_different_metric( + all_dataset_names, + all_sequence_names, + seq_results_list[distortion_metric], + results_list[distortion_metric]) + frame_data, results_list[distortion_metric] = \ + seq_frame_data, seq_results_list[distortion_metric] + else: + print_results(all_dataset_names, results_list[distortion_metric]) + + if plot_rd_curve: + if compare_between == 'sequence': + names = [] + for _, value in all_sequence_names.items(): + names += value + else: + names = all_dataset_names + if plot_scheme == 'combined' and len(names) > 7: + warnings.warn('plotting in combined mode with more than 7 datasets/sequences' + ' is not supported') + else: + matplotlib_plt(names, frame_data, os.path.join(plot_path, f'{frame_type}_frame'), + distortion_metric, plot_scheme=plot_scheme) + + +def main(argv): + matplotlib.use('Agg') + plt.rcParams.update({ + 'grid.color': '0.5', + 'grid.linewidth': 0.5, + 'savefig.dpi': 300 + }) + + args = parse_args(argv) + + stdout = None + if args.output_path != 'stdout' and args.output_path.split('.')[-1] in ['txt', 'TXT']: + stdout = sys.stdout + sys.stdout = open(args.output_path, 'w') + + base_method_name = args.base_method + assert len(args.log_paths) % 2 == 0, \ + 'log paths shoud include both the method name and the corresponding log path' + log_paths = {} + for i in range(len(args.log_paths)//2): + log_paths[args.log_paths[2*i]] = args.log_paths[2*i+1] + assert base_method_name in log_paths, 'log paths must include the base method' + + if args.plot_scheme is None: + args.plot_scheme = 'combined' if args.compare_between == 'class' else 'separate' + if len(args.plot_path) > 0: + create_folder(args.plot_path) + + json_dict = {} # model -> dataset -> seq -> [models] + ds_seq_names = {} + seq_consistency = True + for key_method, json_log_path in log_paths.items(): + json_dict[key_method] = {} + with open(json_log_path) as json_file: + json_data = json.load(json_file) + for ds_name in json_data: + json_dict[key_method][ds_name] = {} + if ds_name not in ds_seq_names: + ds_seq_names[ds_name] = set(json_data[ds_name].keys()) + else: + if ds_seq_names[ds_name] != set(json_data[ds_name].keys()): + seq_consistency = False + for seq in json_data[ds_name]: + json_dict[key_method][ds_name][seq] = {} + for rate_point in sorted(list(json_data[ds_name][seq].keys())): + if args.rate_exclude is not None and rate_point in args.rate_exclude: + continue + json_dict[key_method][ds_name][seq][rate_point] = \ + json_data[ds_name][seq][rate_point] + if not seq_consistency: + warnings.warn('inconsistency found in the sequences tested in each dataset') + + for distortion_metric in args.distortion_metrics: + print(f'result for: {distortion_metric.upper()}') + compare(json_dict, ds_seq_names, base_method_name, args.compare_between, args.plot_path, + args.plot_scheme, distortion_metric, args.plot_rd_curve, + args.compare_frame_type) + + if stdout: + sys.stdout.close() + sys.stdout = stdout + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/requirements.txt b/requirements.txt index 21ad776..00e16fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,10 @@ -numpy>=1.20.0 -scipy -matplotlib -tqdm bd-metric +cmake +matplotlib +ninja +numpy pillow +psutil pybind11 +scipy +tqdm diff --git a/src/cpp/install.sh b/src/cpp/install.sh new file mode 100644 index 0000000..1e5a323 --- /dev/null +++ b/src/cpp/install.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +start=$(date +%s) +pip install --no-build-isolation . +end=$(date +%s) +runtime=$((end - start)) +echo "Execution time: $runtime seconds" diff --git a/src/cpp/py_rans/bind.cpp b/src/cpp/py_rans/bind.cpp new file mode 100644 index 0000000..9cc7f96 --- /dev/null +++ b/src/cpp/py_rans/bind.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "py_rans.h" + +#include +#include +#include +#include +#include + +namespace py = pybind11; + +PYBIND11_MODULE(MLCodec_extensions_cpp, m) +{ + py::class_(m, "RansEncoder") + .def(py::init<>()) + .def("encode_y", py::overload_cast&>(&RansEncoder::encode_y)) + .def("encode_z", py::overload_cast&, const int, const int>( + &RansEncoder::encode_z)) + .def("flush", &RansEncoder::flush) + .def("get_encoded_stream", &RansEncoder::get_encoded_stream) + .def("reset", &RansEncoder::reset) + .def("set_cdf", + py::overload_cast&, const py::array_t&, const int>( + &RansEncoder::set_cdf)) + .def("set_entropy_coder_parallel", &RansEncoder::set_entropy_coder_parallel); + + py::class_(m, "RansDecoder") + .def(py::init<>()) + .def("set_stream", py::overload_cast&>(&RansDecoder::set_stream)) + .def("decode_y", py::overload_cast&>(&RansDecoder::decode_y)) + .def("decode_z", &RansDecoder::decode_z) + .def("set_cdf", + py::overload_cast&, const py::array_t&, const int>( + &RansDecoder::set_cdf)) + .def("set_entropy_coder_parallel", &RansDecoder::set_entropy_coder_parallel); + + m.def("pmf_to_quantized_cdf", &pmf_to_quantized_cdf, "Return quantized CDF for a given PMF"); +} diff --git a/src/cpp/py_rans/py_rans.cpp b/src/cpp/py_rans/py_rans.cpp index 1f5d047..1dbc82e 100644 --- a/src/cpp/py_rans/py_rans.cpp +++ b/src/cpp/py_rans/py_rans.cpp @@ -4,390 +4,497 @@ #include "py_rans.h" #include -#include #include #include #include namespace py = pybind11; -RansEncoder::RansEncoder() +// Count trailing identical zero bytes shared between two encoded streams. +// This allows overlapping the reversed stream to save space. +static int compute_identical_bytes(const std::vector& a, int na, + const std::vector& b, int nb) { - m_encoder0 = std::make_shared(); - m_encoder1 = std::make_shared(); + int identical_bytes = 0; + int check_bytes = std::min({ na, nb, 8 }); + for (int i = 0; i < check_bytes; i++) { + if (a[na - 1 - i] != 0) { + break; + } + if (b[nb - 1 - i] != 0) { + break; + } + identical_bytes++; + } + if (identical_bytes == 0 && a[na - 1] == b[nb - 1]) { + identical_bytes = 1; + } + return identical_bytes; } -void RansEncoder::encode_y(const py::array_t& symbols, const int cdf_group_index) +std::vector pmf_to_quantized_cdf(const std::vector& pmf) { - py::buffer_info symbols_buf = symbols.request(); - int16_t* symbols_ptr = static_cast(symbols_buf.ptr); + /* NOTE(begaintj): ported from `ryg_rans` public implementation. Not optimal + * although it's only run once per model after training. See TF/compression + * implementation for an optimized version. */ + constexpr int precision = 16; + constexpr uint32_t prob_max = (1u << precision); + constexpr int min_freq = 1; - int symbolSize = static_cast(symbols.size()); - if (m_use_two_encoders) { - int symbolSize0 = symbolSize / 2; - int symbolSize1 = symbolSize - symbolSize0; - - auto vec_symbols0 = std::make_shared>(symbolSize0); - memcpy(vec_symbols0->data(), symbols_ptr, symbolSize0 * sizeof(int16_t)); - m_encoder0->encode_y(vec_symbols0, cdf_group_index); - auto vec_symbols1 = std::make_shared>(symbolSize1); - memcpy(vec_symbols1->data(), symbols_ptr + symbolSize0, symbolSize1 * sizeof(int16_t)); - m_encoder1->encode_y(vec_symbols1, cdf_group_index); - } else { - auto vec_symbols0 = std::make_shared>(symbolSize); - memcpy(vec_symbols0->data(), symbols_ptr, symbolSize * sizeof(int16_t)); - m_encoder0->encode_y(vec_symbols0, cdf_group_index); + std::vector cdf(pmf.size() + 1); + cdf[0] = 0; /* freq 0 */ + + std::transform(pmf.begin(), pmf.end(), cdf.begin() + 1, + [=](float p) { return static_cast(p * prob_max + 0.5); }); + + const uint32_t total = std::accumulate(cdf.begin(), cdf.end(), 0); + + std::transform(cdf.begin(), cdf.end(), cdf.begin(), [=](uint32_t p) { + return static_cast(((static_cast(prob_max) * p) / total)); + }); + + std::partial_sum(cdf.begin(), cdf.end(), cdf.begin()); + cdf.back() = prob_max; + + for (int i = 0; i < static_cast(cdf.size() - 1); ++i) { + if (cdf[i] + min_freq > cdf[i + 1]) { + /* Try to steal frequency from low-frequency symbols */ + uint32_t best_freq = ~0u; + int best_steal = -1; + for (int j = 0; j < static_cast(cdf.size()) - 1; ++j) { + uint32_t freq = cdf[j + 1] - cdf[j]; + if (freq >= min_freq * 2 && freq < best_freq) { + best_freq = freq; + best_steal = j; + } + } + + assert(best_steal != -1); + + if (best_steal < i) { + for (int j = best_steal + 1; j <= i; ++j) { + cdf[j] -= min_freq; + } + } else { + assert(best_steal > i); + for (int j = i + 1; j <= best_steal; ++j) { + cdf[j] += min_freq; + } + } + } } + + assert(cdf[0] == 0); + assert(cdf.back() == prob_max); + for (int i = 0; i < static_cast(cdf.size()) - 1; ++i) { + assert(cdf[i + 1] > cdf[i]); + } + + return cdf; } -void RansEncoder::encode_z(const py::array_t& symbols, const int cdf_group_index, - const int start_offset, const int per_channel_size) +RansEncoder::RansEncoder() { - py::buffer_info symbols_buf = symbols.request(); - int8_t* symbols_ptr = static_cast(symbols_buf.ptr); + m_encoders.resize(MAX_EC_PARALLEL); + for (int i = 0; i < MAX_EC_PARALLEL; i++) { + m_encoders[i] = std::make_shared(); + } +} - int symbolSize = static_cast(symbols.size()); - if (m_use_two_encoders) { - int symbolSize0 = symbolSize / 2; - int symbolSize1 = symbolSize - symbolSize0; - int channel_half = symbolSize0 / per_channel_size; - - auto vec_symbols0 = std::make_shared>(symbolSize0); - memcpy(vec_symbols0->data(), symbols_ptr, symbolSize0 * sizeof(int8_t)); - m_encoder0->encode_z(vec_symbols0, cdf_group_index, start_offset, per_channel_size); - auto vec_symbols1 = std::make_shared>(symbolSize1); - memcpy(vec_symbols1->data(), symbols_ptr + symbolSize0, symbolSize1 * sizeof(int8_t)); - m_encoder1->encode_z(vec_symbols1, cdf_group_index, start_offset + channel_half, - per_channel_size); - } else { - auto vec_symbols0 = std::make_shared>(symbolSize); - memcpy(vec_symbols0->data(), symbols_ptr, symbolSize * sizeof(int8_t)); - m_encoder0->encode_z(vec_symbols0, cdf_group_index, start_offset, per_channel_size); +void RansEncoder::encode_y(const std::shared_ptr>& symbols, const int symbolSize) +{ + int n = m_entropy_coder_parallel; + int size0 = symbolSize / n; + for (int i = 0; i < n - 1; i++) { + m_encoders[i]->encode_y(symbols, size0, size0 * i); } + m_encoders[n - 1]->encode_y(symbols, symbolSize - size0 * (n - 1), size0 * (n - 1)); } -int RansEncoder::add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, - const py::array_t& offsets) +void RansEncoder::encode_y(const py::array_t& symbols) { - py::buffer_info cdfs_sizes_buf = cdfs_sizes.request(); - py::buffer_info offsets_buf = offsets.request(); - int32_t* cdfs_sizes_ptr = static_cast(cdfs_sizes_buf.ptr); - int32_t* offsets_ptr = static_cast(offsets_buf.ptr); + py::buffer_info symbols_buf = symbols.request(); + int16_t* symbols_ptr = static_cast(symbols_buf.ptr); - int cdf_num = static_cast(cdfs_sizes.size()); - auto vec_cdfs_sizes = std::make_shared>(cdf_num); - memcpy(vec_cdfs_sizes->data(), cdfs_sizes_ptr, sizeof(int32_t) * cdf_num); - auto vec_offsets = std::make_shared>(offsets.size()); - memcpy(vec_offsets->data(), offsets_ptr, sizeof(int32_t) * offsets.size()); + int symbolSize = static_cast(symbols.size()); + auto vec_symbols = std::make_shared>(symbolSize); + std::copy(symbols_ptr, symbols_ptr + symbolSize, vec_symbols->data()); + encode_y(vec_symbols, symbolSize); +} - int per_vector_size = static_cast(cdfs.size() / cdf_num); - auto vec_cdfs = std::make_shared>>(cdf_num); - auto cdfs_raw = cdfs.unchecked<2>(); - for (int i = 0; i < cdf_num; i++) { - std::vector t(per_vector_size); - memcpy(t.data(), cdfs_raw.data(i, 0), sizeof(int32_t) * per_vector_size); - vec_cdfs->at(i) = t; +void RansEncoder::encode_z(const std::shared_ptr>& symbols, + const int cdf_offset, const int ch) +{ + int symbolSize = static_cast(symbols->size()); + int n = m_entropy_coder_parallel; + int size0 = symbolSize / n; + for (int i = 0; i < n - 1; i++) { + m_encoders[i]->encode_z(symbols, size0, size0 * i, cdf_offset, ch); } - - int cdf_idx = m_encoder0->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); - m_encoder1->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); - return cdf_idx; + m_encoders[n - 1]->encode_z(symbols, symbolSize - size0 * (n - 1), size0 * (n - 1), cdf_offset, ch); } -void RansEncoder::empty_cdf_buffer() +void RansEncoder::encode_z(const py::array_t& symbols, const int cdf_offset, const int ch) { - m_encoder0->empty_cdf_buffer(); - m_encoder1->empty_cdf_buffer(); + py::buffer_info symbols_buf = symbols.request(); + int8_t* symbols_ptr = static_cast(symbols_buf.ptr); + + int symbolSize = static_cast(symbols.size()); + auto vec_symbols = std::make_shared>(symbolSize); + std::copy(symbols_ptr, symbols_ptr + symbolSize, vec_symbols->data()); + encode_z(vec_symbols, cdf_offset, ch); } void RansEncoder::flush() { - m_encoder0->flush(); - m_encoder1->flush(); + int n = m_entropy_coder_parallel; + for (int i = 0; i < n; i++) { + m_encoders[i]->flush(); + } } py::array_t RansEncoder::get_encoded_stream() { - if (m_use_two_encoders) { - auto result0 = m_encoder0->get_encoded_stream(); - int nbytes0 = static_cast(result0->size()); - auto result1 = m_encoder1->get_encoded_stream(); - int nbytes1 = static_cast(result1->size()); - - int identical_bytes = 0; - int check_bytes = std::min(nbytes0, nbytes1); - check_bytes = std::min(check_bytes, 8); - for (int i = 0; i < check_bytes; i++) { - if (result0->at(nbytes0 - 1 - i) != 0) { - break; - } - if (result1->at(nbytes1 - 1 - i) != 0) { - break; - } - identical_bytes++; - } - if (identical_bytes == 0 && result0->at(nbytes0 - 1) == result1->at(nbytes1 - 1)) { - identical_bytes = 1; - } + int n = m_entropy_coder_parallel; + + // Collect all encoded streams + std::vector>> results(n); + std::vector nbytes(n); + for (int i = 0; i < n; i++) { + results[i] = m_encoders[i]->get_encoded_stream(); + nbytes[i] = static_cast(results[i]->size()); + } - py::array_t stream(nbytes0 + nbytes1 - identical_bytes); + if (n == 1) { + /** + * The input arguments to py::array_t constructor are array size and stride. + * The code may fail to perform correct encoding-decoding by omitting array stride. + * It would be more robust by explicitly specifying the stride. + * + * By only passing the array size, i.e., "py::array_t stream(nbytes0);", + * our empirical results are as follows: + * pybind11==3.0.1, numpy==2.3.3: succeeded + * pybind11==2.10.4, numpy==1.26.0: succeeded + * pybind11==2.10.4, numpy==2.3.3: failed. the array stride defaults to 0 + */ + py::array_t stream({ nbytes[0] }, { sizeof(uint8_t) }); py::buffer_info stream_buf = stream.request(); uint8_t* stream_ptr = static_cast(stream_buf.ptr); - - std::copy(result0->begin(), result0->end(), stream_ptr); - std::reverse_copy(result1->begin(), result1->end() - identical_bytes, stream_ptr + nbytes0); + std::copy(results[0]->begin(), results[0]->end(), stream_ptr); return stream; } - auto result0 = m_encoder0->get_encoded_stream(); - int nbytes0 = static_cast(result0->size()); + // For n >= 2, streams are paired: (0,1), (2,3), ... + // Each pair is merged: stream[2k] forward + stream[2k+1] reversed with zero-byte overlap. + // If n is odd, the last stream stands alone (forward only). + int num_pairs = n / 2; + bool has_tail = (n % 2 != 0); + + // Compute group sizes (each pair merged) and the tail + std::vector group_sizes(num_pairs); + std::vector identical(num_pairs); + for (int p = 0; p < num_pairs; p++) { + int i0 = p * 2; + int i1 = p * 2 + 1; + identical[p] = compute_identical_bytes(*results[i0], nbytes[i0], *results[i1], nbytes[i1]); + group_sizes[p] = nbytes[i0] + nbytes[i1] - identical[p]; + } + int tail_size = has_tail ? nbytes[n - 1] : 0; + + // Header: (num_pairs - 1 + has_tail) int32_t offsets + // For n==2 (1 pair, no tail): 0 offsets, no header + int num_offsets = num_pairs - 1 + (has_tail ? 1 : 0); + int header_size = num_offsets * 4; + + int total_size = header_size; + for (int p = 0; p < num_pairs; p++) { + total_size += group_sizes[p]; + } + total_size += tail_size; - py::array_t stream(nbytes0); + py::array_t stream({ total_size }, { sizeof(uint8_t) }); py::buffer_info stream_buf = stream.request(); uint8_t* stream_ptr = static_cast(stream_buf.ptr); - std::copy(result0->begin(), result0->end(), stream_ptr); + // Write header: cumulative offsets for groups after the first + // offset[k] = cumulative size of groups 0..k (so decoder knows where group k+1 starts) + int cumulative = group_sizes[0]; + for (int k = 0; k < num_offsets; k++) { + *reinterpret_cast(stream_ptr + k * 4) = cumulative; + if (k + 1 < num_pairs) { + cumulative += group_sizes[k + 1]; + } else { + // This offset points to the tail start (== total payload without header) + // Already correct: cumulative == sum of all group_sizes + } + } + + // Write groups + int pos = header_size; + for (int p = 0; p < num_pairs; p++) { + int i0 = p * 2; + int i1 = p * 2 + 1; + std::copy(results[i0]->begin(), results[i0]->end(), stream_ptr + pos); + std::reverse_copy(results[i1]->begin(), results[i1]->end() - identical[p], + stream_ptr + pos + nbytes[i0]); + pos += group_sizes[p]; + } + + // Write tail + if (has_tail) { + std::copy(results[n - 1]->begin(), results[n - 1]->end(), stream_ptr + pos); + } + return stream; } void RansEncoder::reset() { - m_encoder0->reset(); - m_encoder1->reset(); + for (int i = 0; i < MAX_EC_PARALLEL; i++) { + m_encoders[i]->reset(); + } +} + +void RansEncoder::set_cdf(const std::shared_ptr>& cdfs, + const std::shared_ptr>& cdfs_sizes, const int index) +{ + int cdf_num = static_cast(cdfs_sizes->size()); + int per_vector_size = static_cast(cdfs->size() / cdf_num); + auto max_value = std::make_shared>(cdf_num); + auto ransSymbols = std::make_shared>>(cdf_num); + for (int i = 0; i < cdf_num; i++) { + max_value->at(i) = static_cast(cdfs_sizes->at(i) - 2); + + const int32_t* cdf = cdfs->data() + i * per_vector_size; + std::vector ransSym(per_vector_size); + const int ransSize = per_vector_size - 1; + for (int j = 0; j < ransSize; j++) { + ransSym[j] = RansSymbol( + { static_cast(cdf[j]), static_cast(cdf[j + 1] - cdf[j]) }); + } + ransSymbols->at(i) = std::move(ransSym); + } + + for (int i = 0; i < MAX_EC_PARALLEL; i++) { + m_encoders[i]->set_cdf(ransSymbols, max_value, index); + } } -void RansEncoder::set_use_two_encoders(bool b) +void RansEncoder::set_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const int index) { - m_use_two_encoders = b; + py::buffer_info cdfs_buf = cdfs.request(); + py::buffer_info cdfs_sizes_buf = cdfs_sizes.request(); + int32_t* cdfs_ptr = static_cast(cdfs_buf.ptr); + int32_t* cdfs_sizes_ptr = static_cast(cdfs_sizes_buf.ptr); + + auto vec_cdfs = std::make_shared>(cdfs.size()); + std::copy(cdfs_ptr, cdfs_ptr + cdfs.size(), vec_cdfs->data()); + auto vec_cdfs_sizes = std::make_shared>(cdfs_sizes.size()); + std::copy(cdfs_sizes_ptr, cdfs_sizes_ptr + cdfs_sizes.size(), vec_cdfs_sizes->data()); + + set_cdf(vec_cdfs, vec_cdfs_sizes, index); } -bool RansEncoder::get_use_two_encoders() +void RansEncoder::set_entropy_coder_parallel(int n) { - return m_use_two_encoders; + assert(n >= 1 && n <= MAX_EC_PARALLEL); + m_entropy_coder_parallel = n; } RansDecoder::RansDecoder() { - m_decoder0 = std::make_shared(); - m_decoder1 = std::make_shared(); + m_decoded_tensor = std::make_shared>(3840 * 2160 / 16 / 16 * 128 * 2); + m_decoders.resize(MAX_EC_PARALLEL); + for (int i = 0; i < MAX_EC_PARALLEL; i++) { + m_decoders[i] = std::make_shared(); + } } -void RansDecoder::set_stream(const py::array_t& encoded) +void RansDecoder::decode_y(const std::shared_ptr>& indexes, const int indexSize) { - py::buffer_info encoded_buf = encoded.request(); - const uint8_t* encoded_ptr = static_cast(encoded_buf.ptr); - const int encoded_size = static_cast(encoded.size()); - auto stream0 = std::make_shared>(encoded.size()); - std::copy(encoded_ptr, encoded_ptr + encoded_size, stream0->data()); - m_decoder0->set_stream(stream0); - if (m_use_two_decoders) { - auto stream1 = std::make_shared>(encoded.size()); - std::reverse_copy(encoded_ptr, encoded_ptr + encoded_size, stream1->data()); - m_decoder1->set_stream(stream1); + m_current_decoded_tensor_size = indexSize; + if (m_decoded_tensor == nullptr || static_cast(m_decoded_tensor->size()) < indexSize) { + m_decoded_tensor = std::make_shared>(indexSize * 2); + } + int8_t* decoded_ptr = m_decoded_tensor->data(); + + int n = m_entropy_coder_parallel; + int size0 = indexSize / n; + for (int i = 0; i < n - 1; i++) { + m_decoders[i]->decode_y(decoded_ptr, indexes, size0, size0 * i); } + m_decoders[n - 1]->decode_y(decoded_ptr, indexes, indexSize - size0 * (n - 1), size0 * (n - 1)); } -void RansDecoder::decode_y(const py::array_t& indexes, const int cdf_group_index) +void RansDecoder::decode_y(const py::array_t& indexes) { py::buffer_info indexes_buf = indexes.request(); uint8_t* indexes_ptr = static_cast(indexes_buf.ptr); int indexSize = static_cast(indexes.size()); - if (m_use_two_decoders) { - int indexSize0 = indexSize / 2; - int indexSize1 = indexSize - indexSize0; - - auto vec_indexes0 = std::make_shared>(indexSize0); - std::copy(indexes_ptr, indexes_ptr + indexSize0, vec_indexes0->data()); - m_decoder0->decode_y(vec_indexes0, cdf_group_index); - - auto vec_indexes1 = std::make_shared>(indexSize1); - std::copy(indexes_ptr + indexSize0, indexes_ptr + indexSize, vec_indexes1->data()); - m_decoder1->decode_y(vec_indexes1, cdf_group_index); - } else { - auto vec_indexes0 = std::make_shared>(indexSize); - std::copy(indexes_ptr, indexes_ptr + indexSize, vec_indexes0->data()); - m_decoder0->decode_y(vec_indexes0, cdf_group_index); - } + auto vec_indexes = std::make_shared>(indexSize); + std::copy(indexes_ptr, indexes_ptr + indexSize, vec_indexes->data()); + + decode_y(vec_indexes, indexSize); } -py::array_t RansDecoder::decode_and_get_y(const py::array_t& indexes, - const int cdf_group_index) +void RansDecoder::decode_z(const int total_size, const int cdf_offset, const int ch) { - decode_y(indexes, cdf_group_index); - return get_decoded_tensor(); + m_current_decoded_tensor_size = total_size; + if (m_decoded_tensor == nullptr || static_cast(m_decoded_tensor->size()) < total_size) { + m_decoded_tensor = std::make_shared>(total_size * 2); + } + int8_t* decoded_ptr = m_decoded_tensor->data(); + + int n = m_entropy_coder_parallel; + int size0 = total_size / n; + for (int i = 0; i < n - 1; i++) { + m_decoders[i]->decode_z(decoded_ptr, size0, size0 * i, cdf_offset, ch); + } + m_decoders[n - 1]->decode_z(decoded_ptr, total_size - size0 * (n - 1), size0 * (n - 1), + cdf_offset, ch); } -void RansDecoder::decode_z(const int total_size, const int cdf_group_index, const int start_offset, - const int per_channel_size) +std::shared_ptr> RansDecoder::get_decoded_tensor_cpp() { - if (m_use_two_decoders) { - int symbolSize0 = total_size / 2; - int symbolSize1 = total_size - symbolSize0; - int channel_half = symbolSize0 / per_channel_size; - m_decoder0->decode_z(symbolSize0, cdf_group_index, start_offset, per_channel_size); - m_decoder1->decode_z(symbolSize1, cdf_group_index, start_offset + channel_half, - per_channel_size); - } else { - m_decoder0->decode_z(total_size, cdf_group_index, start_offset, per_channel_size); + int n = m_entropy_coder_parallel; + for (int i = 0; i < n; i++) { + m_decoders[i]->wait_for_decoding_finish(); } + return m_decoded_tensor; } -py::array_t RansDecoder::get_decoded_tensor() +void RansDecoder::set_cdf(const std::shared_ptr>& cdfs, + const std::shared_ptr>& cdfs_sizes, const int index) { - if (m_use_two_decoders) { - auto result0 = m_decoder0->get_decoded_tensor(); - const int total_size0 = static_cast(result0->size()); + int cdf_num = static_cast(cdfs_sizes->size()); - auto result1 = m_decoder1->get_decoded_tensor(); - const int total_size1 = static_cast(result1->size()); - py::array_t output(total_size0 + total_size1); - py::buffer_info buf = output.request(); - int8_t* buf_ptr = static_cast(buf.ptr); - std::copy(result0->begin(), result0->end(), buf_ptr); - std::copy(result1->begin(), result1->end(), buf_ptr + total_size0); + int per_vector_size = static_cast(cdfs->size() / cdf_num); + auto vec_cdfs = std::make_shared>>(cdf_num); + auto max_value = std::make_shared>(cdf_num); + for (int i = 0; i < cdf_num; i++) { + max_value->at(i) = static_cast(cdfs_sizes->at(i) - 2); - return output; + std::vector t(per_vector_size); + std::copy(cdfs->data() + i * per_vector_size, + cdfs->data() + i * per_vector_size + per_vector_size, t.data()); + vec_cdfs->at(i) = std::move(t); } - auto result0 = m_decoder0->get_decoded_tensor(); - const int total_size0 = static_cast(result0->size()); - - py::array_t output(total_size0); - py::buffer_info buf = output.request(); - int8_t* buf_ptr = static_cast(buf.ptr); - std::copy(result0->begin(), result0->end(), buf_ptr); - - return output; + for (int i = 0; i < MAX_EC_PARALLEL; i++) { + m_decoders[i]->set_cdf(vec_cdfs, max_value, index); + } } -int RansDecoder::add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, - const py::array_t& offsets) +void RansDecoder::set_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const int index) { + py::buffer_info cdfs_buf = cdfs.request(); py::buffer_info cdfs_sizes_buf = cdfs_sizes.request(); - py::buffer_info offsets_buf = offsets.request(); + int32_t* cdfs_ptr = static_cast(cdfs_buf.ptr); int32_t* cdfs_sizes_ptr = static_cast(cdfs_sizes_buf.ptr); - int32_t* offsets_ptr = static_cast(offsets_buf.ptr); - int cdf_num = static_cast(cdfs_sizes.size()); - auto vec_cdfs_sizes = std::make_shared>(cdf_num); - memcpy(vec_cdfs_sizes->data(), cdfs_sizes_ptr, sizeof(int32_t) * cdf_num); - auto vec_offsets = std::make_shared>(offsets.size()); - memcpy(vec_offsets->data(), offsets_ptr, sizeof(int32_t) * offsets.size()); + auto vec_cdfs = std::make_shared>(cdfs.size()); + std::copy(cdfs_ptr, cdfs_ptr + cdfs.size(), vec_cdfs->data()); + auto vec_cdfs_sizes = std::make_shared>(cdfs_sizes.size()); + std::copy(cdfs_sizes_ptr, cdfs_sizes_ptr + cdfs_sizes.size(), vec_cdfs_sizes->data()); - int per_vector_size = static_cast(cdfs.size() / cdf_num); - auto vec_cdfs = std::make_shared>>(cdf_num); - auto cdfs_raw = cdfs.unchecked<2>(); - for (int i = 0; i < cdf_num; i++) { - std::vector t(per_vector_size); - memcpy(t.data(), cdfs_raw.data(i, 0), sizeof(int32_t) * per_vector_size); - vec_cdfs->at(i) = t; - } - int cdf_idx = m_decoder0->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); - m_decoder1->add_cdf(vec_cdfs, vec_cdfs_sizes, vec_offsets); - return cdf_idx; + set_cdf(vec_cdfs, vec_cdfs_sizes, index); } -void RansDecoder::empty_cdf_buffer() +void RansDecoder::set_entropy_coder_parallel(int n) { - m_decoder0->empty_cdf_buffer(); - m_decoder1->empty_cdf_buffer(); + assert(n >= 1 && n <= MAX_EC_PARALLEL); + m_entropy_coder_parallel = n; } -void RansDecoder::set_use_two_decoders(bool b) +void RansDecoder::set_stream(const uint8_t* ptr, const int size) { - m_use_two_decoders = b; -} + int n = m_entropy_coder_parallel; -bool RansDecoder::get_use_two_decoders() -{ - return m_use_two_decoders; -} - -std::vector pmf_to_quantized_cdf(const std::vector& pmf, int precision) -{ - /* NOTE(begaintj): ported from `ryg_rans` public implementation. Not optimal - * although it's only run once per model after training. See TF/compression - * implementation for an optimized version. */ + if (n == 1) { + auto stream0 = std::make_shared>(size); + std::copy(ptr, ptr + size, stream0->data()); + m_decoders[0]->set_stream(stream0); + return; + } - std::vector cdf(pmf.size() + 1); - cdf[0] = 0; /* freq 0 */ + if (n == 2) { + // No header, entire buffer is one pair + auto stream0 = std::make_shared>(size); + std::copy(ptr, ptr + size, stream0->data()); + m_decoders[0]->set_stream(stream0); - std::transform(pmf.begin(), pmf.end(), cdf.begin() + 1, [=](float p) { - return static_cast(std::round(p * (1 << precision)) + 0.5); - }); + auto stream1 = std::make_shared>(size); + std::reverse_copy(ptr, ptr + size, stream1->data()); + m_decoders[1]->set_stream(stream1); + return; + } - const uint32_t total = std::accumulate(cdf.begin(), cdf.end(), 0); + // n >= 3: header + groups + optional tail + int num_pairs = n / 2; + bool has_tail = (n % 2 != 0); + int num_offsets = num_pairs - 1 + (has_tail ? 1 : 0); + int header_size = num_offsets * 4; - std::transform(cdf.begin(), cdf.end(), cdf.begin(), [precision, total](uint32_t p) { - return static_cast((((1ull << precision) * p) / total)); - }); + // Read cumulative offsets + std::vector offsets(num_offsets); + for (int k = 0; k < num_offsets; k++) { + offsets[k] = *reinterpret_cast(ptr + k * 4); + } - std::partial_sum(cdf.begin(), cdf.end(), cdf.begin()); - cdf.back() = 1 << precision; + // Compute group start/end positions (relative to after header) + const uint8_t* payload = ptr + header_size; + int payload_size = size - header_size; + + std::vector group_start(num_pairs); + std::vector group_size(num_pairs); + group_start[0] = 0; + group_size[0] = offsets[0]; // first offset == size of first group + for (int p = 1; p < num_pairs; p++) { + group_start[p] = offsets[p - 1]; + if (p < num_offsets) { + group_size[p] = offsets[p] - offsets[p - 1]; + } else { + // Last group: extends to end of payload (or to tail start) + int groups_end = has_tail ? offsets[num_offsets - 1] : payload_size; + group_size[p] = groups_end - offsets[p - 1]; + } + } - for (int i = 0; i < static_cast(cdf.size() - 1); ++i) { - if (cdf[i] == cdf[i + 1]) { - /* Try to steal frequency from low-frequency symbols */ - uint32_t best_freq = ~0u; - int best_steal = -1; - for (int j = 0; j < static_cast(cdf.size()) - 1; ++j) { - uint32_t freq = cdf[j + 1] - cdf[j]; - if (freq > 1 && freq < best_freq) { - best_freq = freq; - best_steal = j; - } - } + // Set streams for each pair + for (int p = 0; p < num_pairs; p++) { + int i0 = p * 2; + int i1 = p * 2 + 1; + const uint8_t* group_ptr = payload + group_start[p]; + int gs = group_size[p]; - assert(best_steal != -1); + auto s0 = std::make_shared>(gs); + std::copy(group_ptr, group_ptr + gs, s0->data()); + m_decoders[i0]->set_stream(s0); - if (best_steal < i) { - for (int j = best_steal + 1; j <= i; ++j) { - cdf[j]--; - } - } else { - assert(best_steal > i); - for (int j = i + 1; j <= best_steal; ++j) { - cdf[j]++; - } - } - } + auto s1 = std::make_shared>(gs); + std::reverse_copy(group_ptr, group_ptr + gs, s1->data()); + m_decoders[i1]->set_stream(s1); } - assert(cdf[0] == 0); - assert(cdf.back() == (1u << precision)); - for (int i = 0; i < static_cast(cdf.size()) - 1; ++i) { - assert(cdf[i + 1] > cdf[i]); - } + // Tail + if (has_tail) { + int tail_start = offsets[num_offsets - 1]; + int tail_size = payload_size - tail_start; + const uint8_t* tail_ptr = payload + tail_start; - return cdf; + auto s = std::make_shared>(tail_size); + std::copy(tail_ptr, tail_ptr + tail_size, s->data()); + m_decoders[n - 1]->set_stream(s); + } } -PYBIND11_MODULE(MLCodec_extensions_cpp, m) +void RansDecoder::set_stream(const py::array_t& encoded) { - py::class_(m, "RansEncoder") - .def(py::init<>()) - .def("encode_y", &RansEncoder::encode_y) - .def("encode_z", &RansEncoder::encode_z) - .def("flush", &RansEncoder::flush) - .def("get_encoded_stream", &RansEncoder::get_encoded_stream) - .def("reset", &RansEncoder::reset) - .def("add_cdf", &RansEncoder::add_cdf) - .def("empty_cdf_buffer", &RansEncoder::empty_cdf_buffer) - .def("set_use_two_encoders", &RansEncoder::set_use_two_encoders) - .def("get_use_two_encoders", &RansEncoder::get_use_two_encoders); - - py::class_(m, "RansDecoder") - .def(py::init<>()) - .def("set_stream", &RansDecoder::set_stream) - .def("decode_y", &RansDecoder::decode_y) - .def("decode_and_get_y", &RansDecoder::decode_and_get_y) - .def("decode_z", &RansDecoder::decode_z) - .def("get_decoded_tensor", &RansDecoder::get_decoded_tensor) - .def("add_cdf", &RansDecoder::add_cdf) - .def("empty_cdf_buffer", &RansDecoder::empty_cdf_buffer) - .def("set_use_two_decoders", &RansDecoder::set_use_two_decoders) - .def("get_use_two_decoders", &RansDecoder::get_use_two_decoders); - - m.def("pmf_to_quantized_cdf", &pmf_to_quantized_cdf, "Return quantized CDF for a given PMF"); + py::buffer_info encoded_buf = encoded.request(); + const uint8_t* encoded_ptr = static_cast(encoded_buf.ptr); + const int encoded_size = static_cast(encoded.size()); + set_stream(encoded_ptr, encoded_size); } diff --git a/src/cpp/py_rans/py_rans.h b/src/cpp/py_rans/py_rans.h index c7d223a..5fe733a 100644 --- a/src/cpp/py_rans/py_rans.h +++ b/src/cpp/py_rans/py_rans.h @@ -4,6 +4,7 @@ #pragma once #include "rans.h" #include +#include #include #include @@ -11,6 +12,10 @@ namespace py = pybind11; +constexpr int MAX_EC_PARALLEL = 8; + +std::vector pmf_to_quantized_cdf(const std::vector& pmf); + // the classes in this file only perform the type conversion // from python type (numpy) to C++ type (vector) class RansEncoder { @@ -22,22 +27,24 @@ class RansEncoder { RansEncoder& operator=(const RansEncoder&) = delete; RansEncoder& operator=(RansEncoder&&) = delete; - void encode_y(const py::array_t& symbols, const int cdf_group_index); - void encode_z(const py::array_t& symbols, const int cdf_group_index, - const int start_offset, const int per_channel_size); + // symbols may contain more elements than symbolSize + void encode_y(const std::shared_ptr>& symbols, const int symbolSize); + void encode_y(const py::array_t& symbols); + void encode_z(const std::shared_ptr>& symbols, const int cdf_offset, + const int ch); + void encode_z(const py::array_t& symbols, const int cdf_offset, const int ch); void flush(); py::array_t get_encoded_stream(); void reset(); - int add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, - const py::array_t& offsets); - void empty_cdf_buffer(); - void set_use_two_encoders(bool b); - bool get_use_two_encoders(); + void set_cdf(const std::shared_ptr>& cdfs, + const std::shared_ptr>& cdfs_sizes, const int index); + void set_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const int index); + void set_entropy_coder_parallel(int n); private: - std::shared_ptr m_encoder0; - std::shared_ptr m_encoder1; - bool m_use_two_encoders{ false }; + std::vector> m_encoders; + int m_entropy_coder_parallel{ 1 }; }; class RansDecoder { @@ -49,23 +56,23 @@ class RansDecoder { RansDecoder& operator=(const RansDecoder&) = delete; RansDecoder& operator=(RansDecoder&&) = delete; + void decode_y(const std::shared_ptr>& indexes, const int indexSize); + void decode_y(const py::array_t& indexes); + // if is_stream_nhmw, ch is channel number + // otherwise, ch is per channel element number + void decode_z(const int total_size, const int cdf_offset, const int ch); + std::shared_ptr> get_decoded_tensor_cpp(); + void set_cdf(const std::shared_ptr>& cdfs, + const std::shared_ptr>& cdfs_sizes, const int index); + void set_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, + const int index); + void set_entropy_coder_parallel(int n); void set_stream(const py::array_t&); - - void decode_y(const py::array_t& indexes, const int cdf_group_index); - py::array_t decode_and_get_y(const py::array_t& indexes, const int cdf_group_index); - void decode_z(const int total_size, const int cdf_group_index, const int start_offset, - const int per_channel_size); - py::array_t get_decoded_tensor(); - int add_cdf(const py::array_t& cdfs, const py::array_t& cdfs_sizes, - const py::array_t& offsets); - void empty_cdf_buffer(); - void set_use_two_decoders(bool b); - bool get_use_two_decoders(); + void set_stream(const uint8_t* ptr, const int size); private: - std::shared_ptr m_decoder0; - std::shared_ptr m_decoder1; - bool m_use_two_decoders{ false }; + std::shared_ptr> m_decoded_tensor; + int m_current_decoded_tensor_size{ 0 }; + std::vector> m_decoders; + int m_entropy_coder_parallel{ 1 }; }; - -std::vector pmf_to_quantized_cdf(const std::vector& pmf, int precision); diff --git a/src/cpp/py_rans/rans.cpp b/src/cpp/py_rans/rans.cpp index 11eb342..75ffc29 100644 --- a/src/cpp/py_rans/rans.cpp +++ b/src/cpp/py_rans/rans.cpp @@ -1,134 +1,175 @@ -/* Copyright 2020 InterDigital Communications, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Rans64 extensions from: - * https://fgiesen.wordpress.com/2015/12/21/rans-in-practice/ - * Unbounded range coding from: - * https://github.com/tensorflow/compression/blob/master/tensorflow_compression/cc/kernels/unbounded_index_range_coding_kernels.cc - **/ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. #include "rans.h" #include #include +#include #include - -constexpr uint16_t bypass_precision = 2; /* number of bits in bypass mode */ -constexpr uint16_t max_bypass_val = (1 << bypass_precision) - 1; - -inline void RansEncPutBits(RansState& r, uint8_t*& ptr, uint32_t val) -{ - RansAssert(bypass_precision <= 8); - RansAssert(val < (1u << bypass_precision)); - - constexpr uint32_t freq = 1 << (SCALE_BITS - bypass_precision); - constexpr uint32_t x_max = freq << ENC_RENORM_SHIFT_BITS; - while (r >= x_max) { - *(--ptr) = static_cast(r & 0xff); - r >>= 8; +#include +#include + +constexpr int SCALE_BITS = 16; +constexpr int RANS_SHIFT_BITS = 23; +constexpr uint32_t RANS_BYTE_L = 1u << RANS_SHIFT_BITS; +constexpr int ENC_RENORM_SHIFT_BITS = RANS_SHIFT_BITS - SCALE_BITS + 8; +constexpr uint32_t DEC_MASK = (1u << SCALE_BITS) - 1; +constexpr uint16_t BYPASS_PRECISION = 2; // number of bits in bypass mode +constexpr uint16_t MAX_BYPASS_VAL = (1 << BYPASS_PRECISION) - 1; + +#if defined(__GNUC__) || defined(__clang__) + #define FORCE_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) + #define FORCE_INLINE __forceinline +#else + #define FORCE_INLINE inline +#endif + +FORCE_INLINE void RansDecAdvance(RansState& r, const uint8_t*& ptr, uint32_t start, uint32_t freq) +{ + r = freq * (r >> SCALE_BITS) + (r & DEC_MASK) - start; + + // renormalize + while (r < RANS_BYTE_L) { + r = (r << 8) | *ptr++; } +} - r = (r << bypass_precision) | val; +FORCE_INLINE int32_t RansDecGet(RansState& r) +{ + return r & DEC_MASK; } -inline uint32_t RansDecGetBits(RansState& r, uint8_t*& ptr) +FORCE_INLINE uint32_t RansDecGetBits(RansState& r, const uint8_t*& ptr) { - uint32_t val = r & ((1u << bypass_precision) - 1); + uint32_t val = r & ((1u << BYPASS_PRECISION) - 1); - /* Re-normalize */ - r = r >> bypass_precision; + // renormalize + r = r >> BYPASS_PRECISION; if (r < RANS_BYTE_L) { r = (r << 8) | *ptr++; - RansAssert(r >= RANS_BYTE_L); + assert(r >= RANS_BYTE_L); } return val; } -RansEncoderLib::RansEncoderLib() +FORCE_INLINE void RansDecInit(RansState& r, const uint8_t*& ptr) +{ + r = (*ptr++) << 0; + r |= (*ptr++) << 8; + r |= (*ptr++) << 16; + r |= (*ptr++) << 24; +} + +FORCE_INLINE void RansEncFlush(const RansState& r, uint8_t*& ptr) { - _stream = std::make_shared>(); + ptr -= 4; + ptr[0] = static_cast(r >> 0); + ptr[1] = static_cast(r >> 8); + ptr[2] = static_cast(r >> 16); + ptr[3] = static_cast(r >> 24); } -int RansEncoderLib::add_cdf(const std::shared_ptr>> cdfs, - const std::shared_ptr> cdfs_sizes, - const std::shared_ptr> offsets) +FORCE_INLINE void RansEncInit(RansState& r) { + r = RANS_BYTE_L; +} - auto ransSymbols = std::make_shared>>(cdfs->size()); - for (int i = 0; i < static_cast(cdfs->size()); i++) { - const int32_t* cdf = cdfs->at(i).data(); - std::vector ransSym(cdfs->at(i).size()); - const int ransSize = static_cast(ransSym.size() - 1); - for (int j = 0; j < ransSize; j++) { - ransSym[j] = RansSymbol( - { static_cast(cdf[j]), static_cast(cdf[j + 1] - cdf[j]) }); - } - ransSymbols->at(i) = ransSym; +FORCE_INLINE void RansEncPut(RansState& r, uint8_t*& ptr, uint32_t start, uint32_t freq) +{ + // renormalize + const uint32_t r_max = freq << ENC_RENORM_SHIFT_BITS; + while (r >= r_max) { + // converting to uint8_t will only keep the lowest 8 bits, equal to r & 0xff + *(--ptr) = static_cast(r); + r >>= 8; } - _ransSymbols.push_back(ransSymbols); - _cdfs_sizes.push_back(cdfs_sizes); - _offsets.push_back(offsets); - return static_cast(_ransSymbols.size()) - 1; + r = ((r / freq) << SCALE_BITS) + (r % freq) + start; } -void RansEncoderLib::empty_cdf_buffer() +FORCE_INLINE void RansEncPutBits(RansState& r, uint8_t*& ptr, uint32_t val) { - _ransSymbols.clear(); - _cdfs_sizes.clear(); - _offsets.clear(); + static_assert(BYPASS_PRECISION <= 8); + assert(val < (1u << BYPASS_PRECISION)); + + constexpr uint32_t freq = 1 << (SCALE_BITS - BYPASS_PRECISION); + constexpr uint32_t x_max = freq << ENC_RENORM_SHIFT_BITS; + while (r >= x_max) { + *(--ptr) = static_cast(r); + r >>= 8; + } + + r = (r << BYPASS_PRECISION) | val; } -FORCE_INLINE void RansEncoderLib::encode_one_symbol(uint8_t*& ptr, RansState& rans, const int32_t symbol, - const int32_t cdf_size, const int32_t offset, - const std::vector& ransSymbols) +FORCE_INLINE int8_t decode_one_symbol(const uint8_t*& ptr8, RansState& rans, const int32_t* cdf, + const int8_t max_value) { - const int32_t max_value = cdf_size - 2; - int32_t value = symbol - offset; + const int32_t cum_freq = RansDecGet(rans); - uint32_t raw_val = 0; - if (value < 0) { - raw_val = -2 * value - 1; - value = max_value; - } else if (value >= max_value) { - raw_val = 2 * (value - max_value); - value = max_value; + int s = 1; + while (cdf[s] <= cum_freq) { + s++; } + s--; + + RansDecAdvance(rans, ptr8, cdf[s], cdf[s + 1] - cdf[s]); + + int32_t value = static_cast(s); if (value == max_value) { + // Bypass decoding mode + int32_t val = RansDecGetBits(rans, ptr8); + int32_t n_bypass = val; + + while (val == MAX_BYPASS_VAL) { + val = RansDecGetBits(rans, ptr8); + n_bypass += val; + } + + int32_t raw_val = 0; + for (int j = 0; j < n_bypass; ++j) { + val = RansDecGetBits(rans, ptr8); + raw_val |= val << (j * BYPASS_PRECISION); + } + value = raw_val + max_value; + } + + return static_cast((value % 2 == 1) ? (value + 1) / 2 : -(value + 1) / 2); +} + +FORCE_INLINE void encode_one_symbol(uint8_t*& ptr, RansState& rans, const int32_t symbol, + const int8_t max_value, const std::vector& ransSymbols) +{ + int32_t value = abs(symbol) * 2 - (symbol > 0); + + if (value >= max_value) { + const uint32_t raw_val = value - max_value; + value = max_value; + std::vector bypassBins; bypassBins.reserve(20); - /* Determine the number of bypasses (in bypass_precision size) needed to - * encode the raw value. */ + // Determine the number of bypasses (in BYPASS_PRECISION size) + // needed to encode the raw value. int32_t n_bypass = 0; - while ((raw_val >> (n_bypass * bypass_precision)) != 0) { + while ((raw_val >> (n_bypass * BYPASS_PRECISION)) != 0) { ++n_bypass; } - /* Encode number of bypasses */ + // Encode number of bypasses int32_t val = n_bypass; - while (val >= max_bypass_val) { - bypassBins.push_back(max_bypass_val); - val -= max_bypass_val; + while (val >= MAX_BYPASS_VAL) { + bypassBins.push_back(MAX_BYPASS_VAL); + val -= MAX_BYPASS_VAL; } bypassBins.push_back(static_cast(val)); - /* Encode raw value */ + // Encode raw value for (int32_t j = 0; j < n_bypass; ++j) { - const int32_t val1 = (raw_val >> (j * bypass_precision)) & max_bypass_val; + const int32_t val1 = (raw_val >> (j * BYPASS_PRECISION)) & MAX_BYPASS_VAL; bypassBins.push_back(static_cast(val1)); } @@ -139,184 +180,189 @@ FORCE_INLINE void RansEncoderLib::encode_one_symbol(uint8_t*& ptr, RansState& ra RansEncPut(rans, ptr, ransSymbols[value].start, ransSymbols[value].range); } -void RansEncoderLib::encode_y(const std::shared_ptr> symbols, - const int cdf_group_index) +RansEncoderLib::RansEncoderLib() { - PendingTask p; - p.workType = WorkType::EncodeDecodeY; - p.symbols_y = symbols; - p.cdf_group_index = cdf_group_index; - m_pendingEncodingList.push_back(p); + m_ransSymbols.resize(2); + m_max_value.resize(2); + m_stream_buffer = new uint8_t[max_stream_buffer_size]; + m_stream = std::make_shared>(); + m_thread = std::thread(&RansEncoderLib::worker, this); } -void RansEncoderLib::encode_z(const std::shared_ptr> symbols, - const int cdf_group_index, const int start_offset, - const int per_channel_size) -{ - PendingTask p; - p.workType = WorkType::EncodeDecodeZ; - p.symbols_z = symbols; - p.cdf_group_index = cdf_group_index; - p.start_offset = start_offset; - p.per_channel_size = per_channel_size; - m_pendingEncodingList.push_back(p); -} -#include -FORCE_INLINE void RansEncoderLib::encode_y_internal(uint8_t*& ptr, RansState& rans, - const std::shared_ptr> symbols, - const int cdf_group_index) +RansEncoderLib::~RansEncoderLib() { - // backward loop on symbols from the end; - const int16_t* symbols_ptr = symbols->data(); - const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); - const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); - const int symbol_size = static_cast(symbols->size()); + { + std::lock_guard lk(m_mutex_pending); + m_finish = true; + } + m_cv_pending.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } - for (int i = symbol_size - 1; i >= 0; i--) { - const int32_t combined_symbol = symbols_ptr[i]; - const int32_t cdf_idx = combined_symbol & 0xff; - const int32_t s = combined_symbol >> 8; - encode_one_symbol(ptr, rans, s, cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx], - _ransSymbols[cdf_group_index]->at(cdf_idx)); + if (m_stream_buffer != nullptr) { + delete[] m_stream_buffer; + m_stream_buffer = nullptr; } } -FORCE_INLINE void RansEncoderLib::encode_z_internal(uint8_t*& ptr, RansState& rans, - const std::shared_ptr> symbols, - const int cdf_group_index, const int start_offset, - const int per_channel_size) +void RansEncoderLib::check_buffer_capacity(int symbol_count) { - // backward loop on symbols from the end; - const int8_t* symbols_ptr = symbols->data(); - const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); - const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); - const int symbol_size = static_cast(symbols->size()); - - for (int i = symbol_size - 1; i >= 0; i--) { - const int32_t cdf_idx = i / per_channel_size + start_offset; - encode_one_symbol(ptr, rans, symbols_ptr[i], cdfs_sizes_ptr[cdf_idx], offsets_ptr[cdf_idx], - _ransSymbols[cdf_group_index]->at(cdf_idx)); + // Conservative upper bound: each symbol can emit up to 4 bytes (3 bytes renorm + overhead). + // The flush at the end writes 4 bytes for the final state. + const int required_bytes = symbol_count * 4 + 4; + const int remaining_bytes = static_cast(m_ptr - m_stream_buffer); + if (remaining_bytes < required_bytes) { + throw std::runtime_error("rANS buffer overflow: encoding " + std::to_string(symbol_count) + + " symbols requires up to " + std::to_string(required_bytes) + + " bytes, but only " + std::to_string(remaining_bytes) + + " bytes remain in the buffer (capacity: " + + std::to_string(max_stream_buffer_size) + ")"); } } -void RansEncoderLib::flush() +void RansEncoderLib::encode_y(const std::shared_ptr>& symbols, + const int symbol_size, const int symbol_offset) { - RansState rans; - RansEncInit(rans); - - int32_t total_symbol_size = 0; - for (auto it = m_pendingEncodingList.begin(); it != m_pendingEncodingList.end(); it++) { - if (it->workType == WorkType::EncodeDecodeY) { - total_symbol_size += static_cast(it->symbols_y->size()); - } else if (it->workType == WorkType::EncodeDecodeZ) { - total_symbol_size += static_cast(it->symbols_z->size()); - } - } - - if (total_symbol_size == 0) { - _stream->resize(0); - return; - } - - uint8_t* output = new uint8_t[total_symbol_size]; // too much space ? - uint8_t* ptrEnd = output + total_symbol_size; - uint8_t* ptr = ptrEnd; - assert(ptr != nullptr); - - for (auto it = m_pendingEncodingList.rbegin(); it != m_pendingEncodingList.rend(); it++) { - PendingTask p = *it; - if (p.workType == WorkType::EncodeDecodeY) { - encode_y_internal(ptr, rans, p.symbols_y, p.cdf_group_index); - } else if (p.workType == WorkType::EncodeDecodeZ) { - encode_z_internal(ptr, rans, p.symbols_z, p.cdf_group_index, p.start_offset, - p.per_channel_size); - } + PendingTask p; + p.workType = WorkType::EncodeDecodeY; + p.symbols_y = symbols; + p.symbol_size = symbol_size; + p.symbol_offset = symbol_offset; + { + std::unique_lock lk(m_mutex_pending); + m_pending.push(std::move(p)); } + m_cv_pending.notify_one(); +} - RansEncFlush(rans, ptr); +void RansEncoderLib::encode_y_internal(const std::shared_ptr>& symbols, + const int symbol_size, const int symbol_offset) +{ + check_buffer_capacity(symbol_size); - const int nbytes = static_cast(std::distance(ptr, ptrEnd)); + // backward loop on symbols from the end; + const int16_t* symbols_ptr = symbols->data(); + const int8_t* max_value_ptr = m_max_value[1]->data(); + const std::vector* ransSymbols_ptr = m_ransSymbols[1]->data(); + const int symbol_start = symbol_offset; + const int symbol_end = symbol_offset + symbol_size - 1; - _stream->resize(nbytes); - memcpy(_stream->data(), ptr, nbytes); - delete[] output; + for (int i = symbol_end; i >= symbol_start; i--) { + const int16_t combined_symbol = symbols_ptr[i]; + const int32_t cdf_idx = combined_symbol & 0xff; + const int32_t s = static_cast(combined_symbol >> 8); + encode_one_symbol(m_ptr, m_rans, s, max_value_ptr[cdf_idx], ransSymbols_ptr[cdf_idx]); + } } -std::shared_ptr> RansEncoderLib::get_encoded_stream() +void RansEncoderLib::encode_z(const std::shared_ptr>& symbols, const int symbol_size, + const int symbol_offset, const int cdf_offset, const int ch) { - return _stream; + PendingTask p; + p.workType = WorkType::EncodeDecodeZ; + p.symbols_z = symbols; + p.symbol_size = symbol_size; + p.symbol_offset = symbol_offset; + p.cdf_offset = cdf_offset; + p.ch = ch; + { + std::unique_lock lk(m_mutex_pending); + m_pending.push(std::move(p)); + } + m_cv_pending.notify_one(); } -void RansEncoderLib::reset() +void RansEncoderLib::encode_z_internal(const std::shared_ptr>& symbols, + const int symbol_size, const int symbol_offset, + const int cdf_offset, const int ch) { - m_pendingEncodingList.clear(); - _stream->clear(); -} + check_buffer_capacity(symbol_size); -RansEncoderLibMultiThread::RansEncoderLibMultiThread() - : RansEncoderLib() - , m_finish(false) - , m_result_ready(false) -{ - m_thread = std::thread(&RansEncoderLibMultiThread::worker, this); -} -RansEncoderLibMultiThread::~RansEncoderLibMultiThread() -{ - { - std::lock_guard lk(m_mutex_pending); - std::lock_guard lk1(m_mutex_result); - m_finish = true; + // backward loop on symbols from the end; + const int8_t* symbols_ptr = symbols->data(); + const int8_t* max_value_ptr = m_max_value[0]->data(); + const std::vector* ransSymbols_ptr = m_ransSymbols[0]->data(); + const int symbol_start = symbol_offset; + const int symbol_end = symbol_offset + symbol_size - 1; + + for (int i = symbol_end; i >= symbol_start; i--) { + const int32_t cdf_idx = (i % ch) + cdf_offset; + encode_one_symbol(m_ptr, m_rans, symbols_ptr[i], max_value_ptr[cdf_idx], + ransSymbols_ptr[cdf_idx]); } - m_cv_pending.notify_one(); - m_cv_result.notify_one(); - m_thread.join(); } -void RansEncoderLibMultiThread::flush() +void RansEncoderLib::flush() { PendingTask p; p.workType = WorkType::Flush; { std::unique_lock lk(m_mutex_pending); - m_pending.push_back(p); + m_pending.push(std::move(p)); } m_cv_pending.notify_one(); } -std::shared_ptr> RansEncoderLibMultiThread::get_encoded_stream() +std::shared_ptr> RansEncoderLib::get_encoded_stream() { std::unique_lock lk(m_mutex_result); m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); - return RansEncoderLib::get_encoded_stream(); + return m_stream; } -void RansEncoderLibMultiThread::reset() +void RansEncoderLib::reset() { - RansEncoderLib::reset(); + m_stream->clear(); + + RansEncInit(m_rans); + + uint8_t* ptrEnd = m_stream_buffer + max_stream_buffer_size; + m_ptr = ptrEnd; + std::lock_guard lk(m_mutex_result); m_result_ready = false; } -void RansEncoderLibMultiThread::worker() +void RansEncoderLib::set_cdf(const std::shared_ptr>>& ransSymbols, + const std::shared_ptr>& max_value, const int index) +{ + assert(index < 2); + m_ransSymbols[index] = ransSymbols; + m_max_value[index] = max_value; +} + +void RansEncoderLib::worker() { while (!m_finish) { std::unique_lock lk(m_mutex_pending); - m_cv_pending.wait(lk, [this] { return m_pending.size() > 0 || m_finish; }); + m_cv_pending.wait(lk, [this] { return !m_pending.empty() || m_finish; }); if (m_finish) { - lk.unlock(); break; } - if (m_pending.size() == 0) { - lk.unlock(); - // std::cout << "contine in worker" << std::endl; - continue; - } - while (m_pending.size() > 0) { - auto p = m_pending.front(); - m_pending.pop_front(); + while (!m_pending.empty()) { + auto p = std::move(m_pending.front()); + m_pending.pop(); lk.unlock(); - if (p.workType == WorkType::Flush) { - RansEncoderLib::flush(); + if (p.workType == WorkType::EncodeDecodeY) { + RansEncoderLib::encode_y_internal(p.symbols_y, p.symbol_size, p.symbol_offset); + } else if (p.workType == WorkType::EncodeDecodeZ) { + RansEncoderLib::encode_z_internal(p.symbols_z, p.symbol_size, p.symbol_offset, + p.cdf_offset, p.ch); + } else if (p.workType == WorkType::Flush) { + RansEncFlush(m_rans, m_ptr); + + uint8_t* ptrEnd = m_stream_buffer + max_stream_buffer_size; + const int nbytes = static_cast(std::distance(m_ptr, ptrEnd)); + + if (m_ptr < m_stream_buffer || nbytes > max_stream_buffer_size) { + throw std::runtime_error("rANS stream buffer overflow: encoded size (" + + std::to_string(nbytes) + ") exceeds buffer capacity (" + + std::to_string(max_stream_buffer_size) + ")"); + } + + m_stream->resize(nbytes); + std::copy(m_ptr, m_ptr + nbytes, m_stream->data()); { std::lock_guard lk_result(m_mutex_result); m_result_ready = true; @@ -329,132 +375,27 @@ void RansEncoderLibMultiThread::worker() } } -void RansDecoderLib::set_stream(const std::shared_ptr> encoded) -{ - _stream = encoded; - _ptr8 = (uint8_t*)(_stream->data()); - RansDecInit(_rans, _ptr8); -} - -int RansDecoderLib::add_cdf(const std::shared_ptr>> cdfs, - const std::shared_ptr> cdfs_sizes, - const std::shared_ptr> offsets) -{ - _cdfs.push_back(cdfs); - _cdfs_sizes.push_back(cdfs_sizes); - _offsets.push_back(offsets); - return static_cast(_cdfs.size()) - 1; -} - -void RansDecoderLib::empty_cdf_buffer() -{ - _cdfs.clear(); - _cdfs_sizes.clear(); - _offsets.clear(); -} - -FORCE_INLINE int8_t RansDecoderLib::decode_one_symbol(const int32_t* cdf, const int32_t cdf_size, - const int32_t offset) -{ - const int32_t max_value = cdf_size - 2; - const int32_t cum_freq = static_cast(RansDecGet(_rans)); - - int s = 1; - while (cdf[s++] <= cum_freq) { - } - s -= 2; - - RansDecAdvance(_rans, _ptr8, cdf[s], cdf[s + 1] - cdf[s]); - - int32_t value = static_cast(s); - - if (value == max_value) { - /* Bypass decoding mode */ - int32_t val = RansDecGetBits(_rans, _ptr8); - int32_t n_bypass = val; - - while (val == max_bypass_val) { - val = RansDecGetBits(_rans, _ptr8); - n_bypass += val; - } - - int32_t raw_val = 0; - for (int j = 0; j < n_bypass; ++j) { - val = RansDecGetBits(_rans, _ptr8); - raw_val |= val << (j * bypass_precision); - } - value = raw_val >> 1; - if (raw_val & 1) { - value = -value - 1; - } else { - value += max_value; - } - } - - return static_cast(value + offset); -} - -void RansDecoderLib::decode_y(const std::shared_ptr> indexes, - const int cdf_group_index) -{ - int index_size = static_cast(indexes->size()); - m_decoded = std::make_shared>(index_size); - - int8_t* outout_ptr = m_decoded->data(); - const uint8_t* indexes_ptr = indexes->data(); - const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); - const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); - const auto& cdfs = _cdfs[cdf_group_index]; - for (int i = 0; i < index_size; ++i) { - const int32_t cdf_idx = indexes_ptr[i]; - outout_ptr[i] = decode_one_symbol(cdfs->at(cdf_idx).data(), cdfs_sizes_ptr[cdf_idx], - offsets_ptr[cdf_idx]); - } -} - -void RansDecoderLib::decode_z(const int total_size, const int cdf_group_index, - const int start_offset, const int per_channel_size) -{ - m_decoded = std::make_shared>(total_size); - - int8_t* outout_ptr = m_decoded->data(); - const int32_t* cdfs_sizes_ptr = _cdfs_sizes[cdf_group_index]->data(); - const int32_t* offsets_ptr = _offsets[cdf_group_index]->data(); - const auto& cdfs = _cdfs[cdf_group_index]; - for (int i = 0; i < total_size; ++i) { - const int32_t cdf_idx = i / per_channel_size + start_offset; - outout_ptr[i] = decode_one_symbol(cdfs->at(cdf_idx).data(), cdfs_sizes_ptr[cdf_idx], - offsets_ptr[cdf_idx]); - } -} - -std::shared_ptr> RansDecoderLib::get_decoded_tensor() +RansDecoderLib::RansDecoderLib() { - return m_decoded; + m_cdfs.resize(2); + m_max_value.resize(2); + m_thread = std::thread(&RansDecoderLib::worker, this); } -RansDecoderLibMultiThread::RansDecoderLibMultiThread() - : RansDecoderLib() - , m_finish(false) - , m_result_ready(false) -{ - m_thread = std::thread(&RansDecoderLibMultiThread::worker, this); -} - -RansDecoderLibMultiThread::~RansDecoderLibMultiThread() +RansDecoderLib::~RansDecoderLib() { { std::lock_guard lk(m_mutex_pending); - std::lock_guard lk1(m_mutex_result); m_finish = true; } - m_cv_pending.notify_one(); - m_cv_result.notify_one(); - m_thread.join(); + m_cv_pending.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } } -void RansDecoderLibMultiThread::decode_y(const std::shared_ptr> indexes, - const int cdf_group_index) +void RansDecoderLib::decode_y(int8_t* decoded_ptr, const std::shared_ptr>& indexes, + const int symbol_size, const int symbol_offset) { { std::lock_guard lk(m_mutex_result); @@ -463,16 +404,32 @@ void RansDecoderLibMultiThread::decode_y(const std::shared_ptr lk(m_mutex_pending); - m_pending.push_back(p); + m_pending.push(std::move(p)); } m_cv_pending.notify_one(); } -void RansDecoderLibMultiThread::decode_z(const int total_size, const int cdf_group_index, - const int start_offset, const int per_channel_size) +void RansDecoderLib::decode_y_internal(int8_t* decoded_ptr, + const std::shared_ptr>& indexes, + const int symbol_size, const int symbol_offset) +{ + const uint8_t* indexes_ptr = indexes->data(); + const int8_t* max_value_ptr = m_max_value[1]->data(); + const std::vector* cdfs = m_cdfs[1]->data(); + for (int i = 0; i < symbol_size; ++i) { + const int32_t cdf_idx = indexes_ptr[i + symbol_offset]; + decoded_ptr[i + symbol_offset] = + decode_one_symbol(m_ptr8, m_rans, cdfs[cdf_idx].data(), max_value_ptr[cdf_idx]); + } +} + +void RansDecoderLib::decode_z(int8_t* decoded_ptr, const int symbol_size, const int symbol_offset, + const int cdf_offset, const int ch) { { std::lock_guard lk(m_mutex_result); @@ -480,47 +437,69 @@ void RansDecoderLibMultiThread::decode_z(const int total_size, const int cdf_gro } PendingTask p; p.workType = WorkType::EncodeDecodeZ; - p.total_size = total_size; - p.cdf_group_index = cdf_group_index; - p.start_offset = start_offset; - p.per_channel_size = per_channel_size; + p.decoded_ptr = decoded_ptr; + p.symbol_size = symbol_size; + p.symbol_offset = symbol_offset; + p.cdf_offset = cdf_offset; + p.ch = ch; { std::unique_lock lk(m_mutex_pending); - m_pending.push_back(p); + m_pending.push(std::move(p)); } m_cv_pending.notify_one(); } -std::shared_ptr> RansDecoderLibMultiThread::get_decoded_tensor() +void RansDecoderLib::decode_z_internal(int8_t* decoded_ptr, const int symbol_size, + const int symbol_offset, const int cdf_offset, const int ch) +{ + const int8_t* max_value_ptr = m_max_value[0]->data(); + const std::vector* cdfs = m_cdfs[0]->data(); + + for (int i = 0; i < symbol_size; ++i) { + const int32_t cdf_idx = ((i + symbol_offset) % ch) + cdf_offset; + decoded_ptr[i + symbol_offset] = + decode_one_symbol(m_ptr8, m_rans, cdfs[cdf_idx].data(), max_value_ptr[cdf_idx]); + } +} + +void RansDecoderLib::set_cdf(const std::shared_ptr>>& cdfs, + const std::shared_ptr>& max_value, const int index) +{ + assert(index < 2); + m_cdfs[index] = cdfs; + m_max_value[index] = max_value; +} + +void RansDecoderLib::set_stream(const std::shared_ptr> encoded) +{ + m_stream = encoded; + m_ptr8 = m_stream->data(); + RansDecInit(m_rans, m_ptr8); +} + +bool RansDecoderLib::wait_for_decoding_finish() { std::unique_lock lk(m_mutex_result); m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); - return RansDecoderLib::get_decoded_tensor(); + return true; } -void RansDecoderLibMultiThread::worker() +void RansDecoderLib::worker() { while (!m_finish) { std::unique_lock lk(m_mutex_pending); - m_cv_pending.wait(lk, [this] { return m_pending.size() > 0 || m_finish; }); + m_cv_pending.wait(lk, [this] { return !m_pending.empty() || m_finish; }); if (m_finish) { - lk.unlock(); break; } - if (m_pending.size() == 0) { - lk.unlock(); - // std::cout << "contine in worker" << std::endl; - continue; - } - while (m_pending.size() > 0) { - auto p = m_pending.front(); - m_pending.pop_front(); + while (!m_pending.empty()) { + auto p = std::move(m_pending.front()); + m_pending.pop(); lk.unlock(); if (p.workType == WorkType::EncodeDecodeY) { - RansDecoderLib::decode_y(p.indexes, p.cdf_group_index); + decode_y_internal(p.decoded_ptr, p.indexes, p.symbol_size, p.symbol_offset); } else if (p.workType == WorkType::EncodeDecodeZ) { - RansDecoderLib::decode_z(p.total_size, p.cdf_group_index, p.start_offset, - p.per_channel_size); + decode_z_internal(p.decoded_ptr, p.symbol_size, p.symbol_offset, p.cdf_offset, p.ch); } { std::lock_guard lk_result(m_mutex_result); diff --git a/src/cpp/py_rans/rans.h b/src/cpp/py_rans/rans.h index 995dfee..28e97f2 100644 --- a/src/cpp/py_rans/rans.h +++ b/src/cpp/py_rans/rans.h @@ -1,56 +1,16 @@ -/* Copyright 2020 InterDigital Communications, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. #pragma once #include -#include +#include #include #include -#ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpedantic" - #pragma GCC diagnostic ignored "-Wsign-compare" -#endif - -#ifdef _MSC_VER - #pragma warning(disable : 4244) -#endif - -#include "rans_byte.h" - -#ifdef _MSC_VER - #pragma warning(default : 4244) -#endif - -#ifdef __GNUC__ - #pragma GCC diagnostic pop -#endif - -#ifdef _MSC_VER - #define FORCE_INLINE __forceinline -#endif - -#ifdef __GNUC__ - #define FORCE_INLINE __attribute__((always_inline)) inline -#endif - struct RansSymbol { uint16_t start; - uint16_t range; // range for normal coding and 0 for bypass coding + uint16_t range; }; enum class WorkType { @@ -64,138 +24,110 @@ struct PendingTask { std::shared_ptr> symbols_y; std::shared_ptr> symbols_z; std::shared_ptr> indexes; + int8_t* decoded_ptr{ nullptr }; int total_size{ 0 }; - int cdf_group_index{ 0 }; - int start_offset{ 0 }; - int per_channel_size{ 0 }; + int cdf_offset{ 0 }; + int symbol_size{ 0 }; + int symbol_offset{ 0 }; + int ch{ 0 }; + + PendingTask() = default; + PendingTask(PendingTask&&) noexcept = default; + PendingTask& operator=(PendingTask&&) noexcept = default; + + PendingTask(const PendingTask&) = delete; + PendingTask& operator=(const PendingTask&) = delete; }; +using RansState = uint32_t; + /* NOTE: Warning, we buffer everything for now... In case of large files we * should split the bitstream into chunks... Or for a memory-bounded encoder **/ class RansEncoderLib { public: RansEncoderLib(); - virtual ~RansEncoderLib() = default; + virtual ~RansEncoderLib(); RansEncoderLib(const RansEncoderLib&) = delete; RansEncoderLib(RansEncoderLib&&) = delete; RansEncoderLib& operator=(const RansEncoderLib&) = delete; RansEncoderLib& operator=(RansEncoderLib&&) = delete; - void encode_y(const std::shared_ptr> symbols, const int cdf_group_index); - void encode_z(const std::shared_ptr> symbols, const int cdf_group_index, - const int start_offset, const int per_channel_size); - - FORCE_INLINE void encode_y_internal(uint8_t*& ptr, RansState& rans, - const std::shared_ptr> symbols, - const int cdf_group_index); - FORCE_INLINE void encode_z_internal(uint8_t*& ptr, RansState& rans, - const std::shared_ptr> symbols, - const int cdf_group_index, const int start_offset, - const int per_channel_size); - FORCE_INLINE void encode_one_symbol(uint8_t*& ptr, RansState& rans, const int32_t symbol, - const int32_t cdf_size, const int32_t offset, - const std::vector& ransSymbols); - virtual void flush(); - virtual std::shared_ptr> get_encoded_stream(); - virtual void reset(); - virtual int add_cdf(const std::shared_ptr>> cdfs, - const std::shared_ptr> cdfs_sizes, - const std::shared_ptr> offsets); - virtual void empty_cdf_buffer(); + void check_buffer_capacity(int symbol_count); + void encode_y(const std::shared_ptr>& symbols, const int symbol_size, + const int symbol_offset); + void encode_y_internal(const std::shared_ptr>& symbols, + const int symbol_size, const int symbol_offset); + void encode_z(const std::shared_ptr>& symbols, const int symbol_size, + const int symbol_offset, const int cdf_offset, const int ch); + void encode_z_internal(const std::shared_ptr>& symbols, const int symbol_size, + const int symbol_offset, const int cdf_offset, const int ch); + void flush(); + std::shared_ptr> get_encoded_stream(); + void reset(); + void set_cdf(const std::shared_ptr>>& ransSymbols, + const std::shared_ptr>& max_value, const int index); + void worker(); private: - std::shared_ptr> _stream; - - std::vector>>> _ransSymbols; - std::vector>> _cdfs_sizes; - std::vector>> _offsets; - - std::list m_pendingEncodingList; -}; - -class RansEncoderLibMultiThread : public RansEncoderLib { -public: - RansEncoderLibMultiThread(); - virtual ~RansEncoderLibMultiThread(); - virtual void flush() override; - virtual std::shared_ptr> get_encoded_stream() override; - virtual void reset() override; + static const int max_stream_buffer_size = 10 * 1000 * 1000; + uint8_t* m_stream_buffer{ nullptr }; + RansState m_rans; + uint8_t* m_ptr{ nullptr }; + std::shared_ptr> m_stream; - void worker(); + std::vector>>> m_ransSymbols; + std::vector>> m_max_value; -private: - bool m_finish; - bool m_result_ready; + bool m_finish{ false }; + bool m_result_ready{ false }; std::thread m_thread; std::mutex m_mutex_result; std::mutex m_mutex_pending; std::condition_variable m_cv_pending; std::condition_variable m_cv_result; - std::list m_pending; + std::queue m_pending; }; class RansDecoderLib { public: - RansDecoderLib() {} - virtual ~RansDecoderLib() = default; + RansDecoderLib(); + virtual ~RansDecoderLib(); RansDecoderLib(const RansDecoderLib&) = delete; RansDecoderLib(RansDecoderLib&&) = delete; RansDecoderLib& operator=(const RansDecoderLib&) = delete; RansDecoderLib& operator=(RansDecoderLib&&) = delete; - virtual void set_stream(const std::shared_ptr> encoded); - - FORCE_INLINE int8_t decode_one_symbol(const int32_t* cdf, const int32_t cdf_size, - const int32_t offset); - - virtual void decode_y(const std::shared_ptr> indexes, - const int cdf_group_index); - virtual void decode_z(const int total_size, const int cdf_group_index, const int start_offset, - const int per_channel_size); - - virtual std::shared_ptr> get_decoded_tensor(); - - virtual int add_cdf(const std::shared_ptr>> cdfs, - const std::shared_ptr> cdfs_sizes, - const std::shared_ptr> offsets); - virtual void empty_cdf_buffer(); + void decode_y(int8_t* decoded_ptr, const std::shared_ptr>& indexes, + const int symbol_size, const int symbol_offset); + void decode_y_internal(int8_t* decoded_ptr, const std::shared_ptr>& indexes, + const int symbol_size, const int symbol_offset); + void decode_z(int8_t* decoded_ptr, const int symbol_size, const int symbol_offset, + const int cdf_offset, const int ch); + void decode_z_internal(int8_t* decoded_ptr, const int symbol_size, const int symbol_offset, + const int cdf_offset, const int ch); + void set_cdf(const std::shared_ptr>>& cdfs, + const std::shared_ptr>& max_value, const int index); + void set_stream(const std::shared_ptr> encoded); + bool wait_for_decoding_finish(); + void worker(); private: - RansState _rans; - uint8_t* _ptr8; - std::shared_ptr> _stream; - std::shared_ptr> m_decoded; - - std::vector>>> _cdfs; - std::vector>> _cdfs_sizes; - std::vector>> _offsets; -}; + RansState m_rans; + const uint8_t* m_ptr8{ nullptr }; + std::shared_ptr> m_stream; -class RansDecoderLibMultiThread : public RansDecoderLib { -public: - RansDecoderLibMultiThread(); - virtual ~RansDecoderLibMultiThread(); - - virtual void decode_y(const std::shared_ptr> indexes, - const int cdf_group_index) override; - - virtual void decode_z(const int total_size, const int cdf_group_index, const int start_offset, - const int per_channel_size) override; - - virtual std::shared_ptr> get_decoded_tensor() override; + std::vector>>> m_cdfs; + std::vector>> m_max_value; - void worker(); - -private: - bool m_finish; - bool m_result_ready; + bool m_finish{ false }; + bool m_result_ready{ false }; std::thread m_thread; std::mutex m_mutex_result; std::mutex m_mutex_pending; std::condition_variable m_cv_pending; std::condition_variable m_cv_result; - std::list m_pending; -}; \ No newline at end of file + std::queue m_pending; +}; diff --git a/src/cpp/pyproject.toml b/src/cpp/pyproject.toml new file mode 100644 index 0000000..9787c3b --- /dev/null +++ b/src/cpp/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/src/cpp/setup.py b/src/cpp/setup.py index 7e1b036..a86631b 100644 --- a/src/cpp/setup.py +++ b/src/cpp/setup.py @@ -7,7 +7,7 @@ from pybind11.setup_helpers import Pybind11Extension, build_ext -if sys.platform == "win32": +if sys.platform == 'win32': extra_compile_args = ['/std:c++17', '/O2', '/W4', '/WX', '/wd4100'] extra_link_args = [] else: @@ -16,7 +16,7 @@ setup( - name="MLCodec_extensions_cpp", + name='MLCodec_extensions_cpp', ext_modules=[ Pybind11Extension( name='MLCodec_extensions_cpp', @@ -25,7 +25,7 @@ extra_link_args=extra_link_args, ), ], - cmdclass={"build_ext": build_ext}, + cmdclass={'build_ext': build_ext}, zip_safe=False, - python_requires=">=3.12", + python_requires='>=3.12', ) diff --git a/src/datasets/image_dataset.py b/src/datasets/image_dataset.py new file mode 100644 index 0000000..8c184a2 --- /dev/null +++ b/src/datasets/image_dataset.py @@ -0,0 +1,72 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import json +import numpy as np +import os +import random +import torch + +from PIL import Image +from torch.utils.data import Dataset + +from ..utils.transforms import rgb2ycbcr_np + + +class ImageFolder(Dataset): + def __init__(self, root_folder_path, patch_h, patch_w, qp_num, lambdas): + self.root_folder_path = root_folder_path + with open(os.path.join(root_folder_path, 'description.json')) as json_file: + self.dataset = json.load(json_file) + + self.dataset_length = len(self.dataset) + self.patch_h = patch_h + self.patch_w = patch_w + self.qp_num = qp_num + self.lambdas = lambdas + + def __getitem__(self, index): + image_path = os.path.join(self.root_folder_path, self.dataset[index]) + img = Image.open(image_path).convert('RGB') + width, height = img.size + + pad_height = self.patch_h - height + pad_width = self.patch_w - width + pad_height = max(0, pad_height) + pad_width = max(0, pad_width) + pad_size = ((pad_height // 2, pad_height - pad_height // 2), + (pad_width // 2, pad_width - pad_width // 2), + (0, 0),) + padded_height = height + pad_height + padded_width = width + pad_width + y = random.randint(0, padded_height - self.patch_h) + x = random.randint(0, padded_width - self.patch_w) + + if random.choice([True, False]): + img = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + img = np.array(img).astype(np.uint8) + img = np.pad(img, pad_size, mode='constant') + img = img[y:y+self.patch_h, x:x+self.patch_w, :] + + img = img.astype(np.float32) / 255.0 + img = rgb2ycbcr_np(img) + img = img - 0.5 + img = torch.as_tensor(img, dtype=torch.float32) + img = img.permute(2, 0, 1).contiguous() + # img in [3, H, W] + + curr_qp = random.randint(0, self.qp_num - 1) + curr_lambda = self.lambdas[curr_qp] + curr_qp = torch.tensor(curr_qp, dtype=torch.int32) + curr_lambda = torch.tensor(curr_lambda, dtype=torch.float32) + return [img, curr_qp, curr_lambda] + + def __len__(self): + return self.dataset_length + + def get_patch_size(self): + return self.patch_w, self.patch_h + + def set_patch_size(self, patch_width, patch_height): + self.patch_w = patch_width + self.patch_h = patch_height diff --git a/src/datasets/video_dataset.py b/src/datasets/video_dataset.py new file mode 100644 index 0000000..aeb0af2 --- /dev/null +++ b/src/datasets/video_dataset.py @@ -0,0 +1,123 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import json +import numpy as np +import os +import random +import torch + +from PIL import Image +from torch.utils.data import Dataset + +from ..utils.transforms import rgb2ycbcr_np + + +class VideoFolder(Dataset): + def __init__(self, root_folder_path, patch_h, patch_w, qp_num, lambdas, frame_num=5, + group_of_pictures=1): + self.root_folder_path = root_folder_path + with open(os.path.join(self.root_folder_path, 'description.json')) as json_file: + desc = json.load(json_file) + self.seqs = desc['seqs'] + self.frames = desc['frames'] + + self.dataset_length = len(self.seqs) + self.patch_h = patch_h + self.patch_w = patch_w + self.qp_num = qp_num + self.lambdas = lambdas + self.frame_num = frame_num + self.group_of_pictures = group_of_pictures + + def __getitem__(self, index): + seq = self.seqs[index] + height = seq['height'] + width = seq['width'] + seq_length = seq['seq_length'] + seq_path = seq['path'] + + img_indexes = [] + if self.frame_num < seq_length: + frame_index = random.randint(0, seq_length - self.frame_num - 1) + img_indexes = list(range(frame_index, frame_index + self.frame_num)) + else: + increasing = True + frame_index = 0 + while len(img_indexes) < self.frame_num: + img_indexes.append(frame_index) + if increasing: + if frame_index == seq_length - 1: + frame_index -= 1 + increasing = False + else: + frame_index += 1 + else: + if frame_index == 0: + frame_index += 1 + increasing = True + else: + frame_index -= 1 + + flip = random.choice([True, False]) + + pad_height = self.patch_h - height + pad_width = self.patch_w - width + pad_height = max(0, pad_height) + pad_width = max(0, pad_width) + pad_size = ((pad_height // 2, pad_height - pad_height // 2), + (pad_width // 2, pad_width - pad_width // 2), + (0, 0),) + padded_height = height + pad_height + padded_width = width + pad_width + y = random.randint(0, padded_height - self.patch_h) + x = random.randint(0, padded_width - self.patch_w) + + video_data = [] + curr_img_group = [] + for img_index in img_indexes: + img_path = os.path.join(self.root_folder_path, seq_path, self.frames[img_index]) + img = Image.open(img_path).convert('RGB') + if flip: + img = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + img = np.array(img).astype(np.uint8) + img = np.pad(img, pad_size, mode='constant') + + img = img[y:y+self.patch_h, x:x+self.patch_w, :] + img = img.astype(np.float32) / 255.0 + img = rgb2ycbcr_np(img) + img = img - 0.5 + img = torch.as_tensor(img, dtype=torch.float32) + img = img.permute(2, 0, 1).contiguous() + # img in [3, H, W] + if len(video_data) == 0: + video_data.append(img) + else: + curr_img_group.append(img) + if len(curr_img_group) == self.group_of_pictures: + img = torch.cat(curr_img_group, dim=0) + video_data.append(img) + curr_img_group = [] + + curr_qp = random.randint(0, self.qp_num - 1) + curr_lambda = self.lambdas[curr_qp] + video_data.append(torch.tensor(curr_qp, dtype=torch.int32)) + video_data.append(torch.tensor(curr_lambda, dtype=torch.float32)) + + return video_data + + def __len__(self): + return self.dataset_length + + def get_frame_num(self): + return self.frame_num + + def get_patch_size(self): + return self.patch_w, self.patch_h + + def set_frame_num(self, frame_num): + self.frame_num = frame_num + + def set_patch_size(self, patch_width, patch_height): + self.patch_w = patch_width + self.patch_h = patch_height diff --git a/src/layers/extensions/inference/bind.cpp b/src/layers/extensions/inference/bind.cpp index 0bc8e24..3bf01f5 100644 --- a/src/layers/extensions/inference/bind.cpp +++ b/src/layers/extensions/inference/bind.cpp @@ -1,36 +1,39 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#include "def.h" #include +#include "dmc_htl_proxy.h" +#include "dmc_hts_proxy.h" +#include "dmc_ld_proxy.h" +#include "dmci_proxy.h" + PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("process_with_mask_cuda", &process_with_mask_cuda); - m.def("combine_for_reading_2x_cuda", &combine_for_reading_2x_cuda); - m.def("restore_y_2x_cuda", &restore_y_2x_cuda); - m.def("restore_y_4x_cuda", &restore_y_4x_cuda); - m.def("build_index_dec_cuda", &build_index_dec_cuda); - m.def("build_index_enc_cuda", &build_index_enc_cuda); - m.def("bias_quant_cuda", &bias_quant_cuda); - m.def("round_and_to_int8_cuda", &round_and_to_int8_cuda); - m.def("clamp_reciprocal_with_quant_cuda", &clamp_reciprocal_with_quant_cuda); - m.def("add_and_multiply_cuda", &add_and_multiply_cuda); - m.def("bias_pixel_shuffle_8_cuda", &bias_pixel_shuffle_8_cuda); - m.def("replicate_pad_cuda", &replicate_pad_cuda); - m.def("bias_wsilu_depthwise_conv2d_cuda", &bias_wsilu_depthwise_conv2d_cuda); + py::class_(m, "DMCIProxy") + .def(py::init<>()) + .def("set_param", &DMCIProxy::set_param) + .def("compress", &DMCIProxy::compress) + .def("decompress", &DMCIProxy::decompress); + + py::class_(m, "DMCHTLProxy") + .def(py::init<>()) + .def("set_param", &DMCHTLProxy::set_param) + .def("add_ref_feature_from_frame", &DMCHTLProxy::add_ref_feature_from_frame) + .def("compress", &DMCHTLProxy::compress) + .def("decompress", &DMCHTLProxy::decompress); - py::class_(m, "DepthConvProxy") + py::class_(m, "DMCHTSProxy") .def(py::init<>()) - .def("set_param", &DepthConvProxy::set_param) - .def("set_param_with_adaptor", &DepthConvProxy::set_param_with_adaptor) - .def("forward", &DepthConvProxy::forward) - .def("forward_with_quant_step", &DepthConvProxy::forward_with_quant_step) - .def("forward_with_cat", &DepthConvProxy::forward_with_cat); + .def("set_param", &DMCHTSProxy::set_param) + .def("add_ref_feature_from_frame", &DMCHTSProxy::add_ref_feature_from_frame) + .def("compress", &DMCHTSProxy::compress) + .def("decompress", &DMCHTSProxy::decompress); - py::class_(m, "SubpelConv2xProxy") + py::class_(m, "DMCLDProxy") .def(py::init<>()) - .def("set_param", &SubpelConv2xProxy::set_param) - .def("forward", &SubpelConv2xProxy::forward) - .def("forward_with_cat", &SubpelConv2xProxy::forward_with_cat); + .def("set_param", &DMCLDProxy::set_param) + .def("add_ref_feature_from_frame", &DMCLDProxy::add_ref_feature_from_frame) + .def("compress", &DMCLDProxy::compress) + .def("decompress", &DMCLDProxy::decompress); } diff --git a/src/layers/extensions/inference/common_cpp.h b/src/layers/extensions/inference/common_cpp.h new file mode 100644 index 0000000..5e56fc4 --- /dev/null +++ b/src/layers/extensions/inference/common_cpp.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +class GPUInfo { +public: + GPUInfo() + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + if (deviceCount == 0) { + return; + } + + // only query the first GPU + cudaDeviceProp deviceProp; + cudaGetDeviceProperties(&deviceProp, 0); + computeCapability = deviceProp.major * 10 + deviceProp.minor; + } + ~GPUInfo() {} + +public: + int computeCapability{ 0 }; +}; + +inline GPUInfo& get_gpu_info() +{ + static GPUInfo info; + return info; +} + +inline int get_gpu_sm() +{ + return get_gpu_info().computeCapability; +} diff --git a/src/layers/extensions/inference/common_cu.h b/src/layers/extensions/inference/common_cu.h new file mode 100644 index 0000000..088712b --- /dev/null +++ b/src/layers/extensions/inference/common_cu.h @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "common_cutlass.h" +#include "def_const.h" + +constexpr uint64_t conv_key(uint64_t sm, uint64_t W, uint64_t H, uint64_t C2, uint64_t C1, + uint64_t stride, uint64_t kernel) +{ + /** + * Valid range: + * kernel: 0 - 1 () 2^0 - 2^0 + * stride: 0 - 1 (<<1) 2^1 - 2^1 + * C1: 2^3 - 2^13 (>>1) 2^2 - 2^12 + * C2: 2^3 - 2^13 (<<10) 2^13 - 2^23 + * H: 2^0 - 2^15 (<<24) 2^24 - 2^39 + * W: 2^0 - 2^15 (<<40) 2^40 - 2^55 + * SM: 1 - 0xFF (8bits) (<<56) + */ + assert(C2 <= (1 << 13) && (C2 & 7) == 0 && C1 <= (1 << 13) && (C1 & 7) == 0 && H <= (1 << 15) + && W <= (1 << 15) && sm <= 0xFF); + return kernel | (stride << 1) | (C1 >> 1) | (C2 << 10) | (H << 24) | (W << 40) | (sm << 56); +} + +struct CudaCHW { + int C; + int H; + int W; +}; + +template +__forceinline__ std::tuple get_kernel_config_1D(const at::Tensor& x) +{ + int N = x.numel(); + assert(N % factor == 0); + N /= factor; + const int BLOCK_SIZE = 256; + const dim3 blockDim(BLOCK_SIZE); + const dim3 gridDim((N + BLOCK_SIZE - 1) / BLOCK_SIZE); + + static cudaLaunchAttribute attrs = get_cuda_launch_attribute(); + cudaLaunchConfig_t config; + config.gridDim = gridDim; + config.blockDim = blockDim; + config.dynamicSmemBytes = 0; + config.stream = at::cuda::getCurrentCUDAStream(); + config.attrs = &attrs; + config.numAttrs = 1; + + return { config, N }; +} + +template +__forceinline__ std::tuple get_kernel_config_4D(const int C, + const int H, const int W) +{ + assert(C % factor == 0); + const dim3 gridDim((C / factor + BLOCK_SIZE_X - 1) / BLOCK_SIZE_X, + (W + BLOCK_SIZE_Y - 1) / BLOCK_SIZE_Y, (H + BLOCK_SIZE_Z - 1) / BLOCK_SIZE_Z); + const dim3 blockDim(BLOCK_SIZE_X, BLOCK_SIZE_Y, BLOCK_SIZE_Z); + + static cudaLaunchAttribute attrs = get_cuda_launch_attribute(); + cudaLaunchConfig_t config; + config.gridDim = gridDim; + config.blockDim = blockDim; + config.dynamicSmemBytes = 0; + config.stream = at::cuda::getCurrentCUDAStream(); + config.attrs = &attrs; + config.numAttrs = 1; + return { config, { C / factor, H, W } }; +} + +template +__forceinline__ std::tuple get_kernel_config_4D(const at::Tensor& x) +{ + const int C = x.size(1); + const int H = x.size(2); + const int W = x.size(3); + return get_kernel_config_4D(C, H, W); +} + +struct __align__(2) bool2 +{ + bool x; + bool y; +}; + +template +__forceinline__ __device__ void load2(const T* src, T& dst0, T& dst1) +{ + if constexpr (std::is_same_v) { + half2 v = *reinterpret_cast(src); + dst0 = __low2half(v); + dst1 = __high2half(v); + } else if constexpr (std::is_same_v) { + short2 v = *reinterpret_cast(src); + dst0 = v.x; + dst1 = v.y; + } else if constexpr (std::is_same_v) { + char2 v = *reinterpret_cast(src); + dst0 = v.x; + dst1 = v.y; + } else if constexpr (std::is_same_v) { + uchar2 v = *reinterpret_cast(src); + dst0 = v.x; + dst1 = v.y; + } else if constexpr (std::is_same_v) { + bool2 v = *reinterpret_cast(src); + dst0 = v.x; + dst1 = v.y; + } else { + dst0 = src[0]; + dst1 = src[1]; + } +} + +__forceinline__ __device__ at::Half log(const at::Half& a) +{ + return hlog(a); +} + +__forceinline__ __device__ bool2 make_bool2(bool x, bool y) +{ + bool2 t; + t.x = x; + t.y = y; + return t; +} + +__forceinline__ __device__ at::Half max(const at::Half& a, const at::Half& b) +{ + return __hmax(a, b); +} + +__forceinline__ __device__ at::Half min(const at::Half& a, const at::Half& b) +{ + return __hmin(a, b); +} + +__forceinline__ __device__ at::Half operator*(const at::Half& a, const bool b) +{ + return b ? a : static_cast(0.f); +} + +__forceinline__ __device__ bool operator>(const at::Half& a, const at::Half& b) +{ + return __hgt(a, b); +} + +__forceinline__ __device__ at::Half reciprocal(const at::Half& a) +{ + return hrcp(a); +} + +template +__forceinline__ __device__ void store2(T* dst, T src0, T src1) +{ + if constexpr (std::is_same_v) { + *reinterpret_cast(dst) = __halves2half2(src0, src1); + } else if constexpr (std::is_same_v) { + *reinterpret_cast(dst) = make_short2(src0, src1); + } else if constexpr (std::is_same_v) { + *reinterpret_cast(dst) = make_char2(src0, src1); + } else if constexpr (std::is_same_v) { + *reinterpret_cast(dst) = make_uchar2(src0, src1); + } else if constexpr (std::is_same_v) { + *reinterpret_cast(dst) = make_bool2(src0, src1); + } else { + dst[0] = src0; + dst[1] = src1; + } +} + +__forceinline__ __device__ int16_t to_int16(const at::Half& a) +{ + return static_cast(__half2int_rd(a)); +} + +__forceinline__ __device__ uint8_t to_uint8(const at::Half& a) +{ + return static_cast(__half2uint_rd(a)); +} diff --git a/src/layers/extensions/inference/common_cutlass.h b/src/layers/extensions/inference/common_cutlass.h new file mode 100644 index 0000000..6179c9a --- /dev/null +++ b/src/layers/extensions/inference/common_cutlass.h @@ -0,0 +1,289 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if CURRENT_DEVICE_SM == 90 || CURRENT_DEVICE_SM == 100 + #define cudaGDC() cudaGridDependencySynchronize() +#else + #define cudaGDC() ((void)0) +#endif + +template +CUTLASS_HOST_DEVICE T four(); + +template <> +CUTLASS_HOST_DEVICE float four() +{ + return 4.f; +} + +template <> +CUTLASS_HOST_DEVICE cutlass::half_t four() +{ + uint16_t bits = 0x4400u; + return reinterpret_cast(bits); +} + +__forceinline__ cudaLaunchAttribute get_cuda_launch_attribute() +{ + cudaLaunchAttribute attr; + attr.id = cudaLaunchAttributeProgrammaticStreamSerialization; +#if CURRENT_DEVICE_SM == 90 || CURRENT_DEVICE_SM == 100 + attr.val.programmaticStreamSerializationAllowed = 1; +#else + attr.val.programmaticStreamSerializationAllowed = 0; +#endif + return attr; +} + +__device__ __forceinline__ std::tuple global_idx_chw() +{ + const int c = blockIdx.x * blockDim.x + threadIdx.x; + const int w = blockIdx.y * blockDim.y + threadIdx.y; + const int h = blockIdx.z * blockDim.z + threadIdx.z; + return { c, h, w }; +} + +// T maybe vector type, and may be different from t.dtype +template +struct GPUTensor1D { + GPUTensor1D(at::Tensor& t) : ptr(static_cast(t.data_ptr())) {} + GPUTensor1D(const at::Tensor& t) : ptr(static_cast(t.data_ptr())) {} + GPUTensor1D(std::nullptr_t) : ptr(nullptr) {} + + __device__ T& operator[](int idx) { return ptr[idx]; } + __device__ T& operator[](int idx) const { return ptr[idx]; } + + T* __restrict__ const ptr; +}; + +template +class GPUTensorND : public at::PackedTensorAccessor32 { + using Base = at::PackedTensorAccessor32; + +public: + GPUTensorND(at::Tensor& t) : Base(t.packed_accessor32()) {} + GPUTensorND(const at::Tensor& t) : Base(t.packed_accessor32()) {} + GPUTensorND(std::nullptr_t) : Base(make_null_base()) {} + + static inline Base make_null_base() + { + int32_t sizes[N] = { 0 }; + int32_t strides[N] = { 0 }; + return Base(nullptr, sizes, strides); + } +}; + +template +using GPUTensor2D = GPUTensorND; + +template +using GPUTensor4D = GPUTensorND; + +constexpr int HINT_NUM = 30; +constexpr int HINT_NUM_EX = 96; + +template +struct WSiLUOp; + +template +struct WSiLUOp> { + static const bool kIsHeavy = true; + + CUTLASS_HOST_DEVICE + cutlass::Array operator()(cutlass::Array const& value) const + { + cutlass::epilogue::thread::Sigmoid> sigmoid_op; + cutlass::multiplies> mul; + return mul(value, sigmoid_op(mul(four(), value))); + } +}; + +// clang-format off +// Macro for Sm80 Hint definitions +#define DEFINE_HINT_SM80(N, TB_M, TB_N, TB_K, W_M, W_N, W_K, OP_M, OP_N, OP_K, STAGES) \ +struct Hint##N { \ + using SmArch = cutlass::arch::Sm80; \ + using ShapeThreadBlock = cutlass::gemm::GemmShape; \ + using ShapeWarp = cutlass::gemm::GemmShape; \ + using ShapeOp = cutlass::gemm::GemmShape; \ + static constexpr int Stages = STAGES; \ +} + +// N TB_M TB_N TB_K W_M W_N W_K OP_M OP_N OP_K STAGES +DEFINE_HINT_SM80( 0, 256, 128, 32, 64, 64, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 1, 128, 256, 32, 64, 64, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 2, 128, 128, 32, 64, 64, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 3, 64, 256, 32, 64, 64, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 4, 256, 64, 32, 64, 64, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 5, 64, 128, 32, 32, 64, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 6, 128, 64, 32, 64, 32, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 7, 64, 64, 32, 32, 32, 32, 16, 8, 8, 2); +DEFINE_HINT_SM80( 8, 64, 64, 64, 32, 32, 64, 16, 8, 16, 5); +DEFINE_HINT_SM80( 9, 256, 128, 32, 64, 64, 32, 16, 8, 16, 3); +DEFINE_HINT_SM80( 10, 128, 256, 32, 64, 64, 32, 16, 8, 16, 3); +DEFINE_HINT_SM80( 11, 256, 64, 32, 64, 64, 32, 16, 8, 16, 3); +DEFINE_HINT_SM80( 12, 256, 64, 32, 64, 64, 32, 16, 8, 16, 4); +DEFINE_HINT_SM80( 13, 64, 256, 32, 64, 64, 32, 16, 8, 16, 4); +DEFINE_HINT_SM80( 14, 128, 128, 32, 64, 64, 32, 16, 8, 16, 3); // default Sm80, Sm86, Sm90 +DEFINE_HINT_SM80( 15, 128, 128, 32, 64, 64, 32, 16, 8, 16, 4); +DEFINE_HINT_SM80( 16, 128, 128, 32, 64, 64, 32, 16, 8, 16, 5); +DEFINE_HINT_SM80( 17, 128, 64, 32, 64, 32, 32, 16, 8, 16, 6); +DEFINE_HINT_SM80( 18, 64, 128, 32, 32, 64, 32, 16, 8, 16, 6); +DEFINE_HINT_SM80( 19, 64, 64, 32, 32, 32, 32, 16, 8, 16, 10); +DEFINE_HINT_SM80( 20, 256, 128, 64, 64, 64, 64, 16, 8, 16, 3); +DEFINE_HINT_SM80( 21, 128, 256, 64, 64, 64, 64, 16, 8, 16, 3); +DEFINE_HINT_SM80( 22, 256, 64, 64, 64, 64, 64, 16, 8, 16, 4); +DEFINE_HINT_SM80( 23, 64, 256, 64, 64, 64, 64, 16, 8, 16, 4); +DEFINE_HINT_SM80( 24, 128, 128, 64, 64, 64, 64, 16, 8, 16, 4); +DEFINE_HINT_SM80( 25, 256, 64, 64, 64, 64, 64, 16, 8, 16, 3); +DEFINE_HINT_SM80( 26, 64, 256, 64, 64, 64, 64, 16, 8, 16, 3); +DEFINE_HINT_SM80( 27, 128, 128, 64, 64, 64, 64, 16, 8, 16, 3); +DEFINE_HINT_SM80( 28, 128, 64, 64, 64, 32, 64, 16, 8, 16, 3); +DEFINE_HINT_SM80( 29, 64, 128, 64, 32, 64, 64, 16, 8, 16, 3); + +// Macro for Sm90 Hint definitions +#define DEFINE_HINT_SM90(N, T_M, T_N, T_K, C_X, C_Y, C_Z) \ +struct Hint##N { \ + using SmArch = cutlass::arch::Sm90; \ + using TileShape = cute::Shape; \ + using ClusterShape = cute::Shape; \ + using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecializedCooperative; \ + using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecializedCooperative; \ +} + +// N T_M T_N T_K C_X C_Y C_Z +DEFINE_HINT_SM90( 30, _128, _128, _64, _1, _2, _1); +DEFINE_HINT_SM90( 31, _128, _128, _64, _2, _1, _1); +DEFINE_HINT_SM90( 32, _128, _256, _64, _1, _2, _1); +DEFINE_HINT_SM90( 33, _128, _256, _64, _2, _1, _1); +DEFINE_HINT_SM90( 34, _256, _128, _64, _1, _2, _1); +DEFINE_HINT_SM90( 35, _256, _128, _64, _2, _1, _1); +DEFINE_HINT_SM90( 36, _256, _256, _64, _1, _2, _1); +DEFINE_HINT_SM90( 37, _256, _256, _64, _2, _1, _1); + +// Macros for Sm100 Hint definitions with different schedule combinations +// Type A: TmaWarpSpecialized2Sm + KernelTmaWarpSpecialized2SmSm100 +#define DEFINE_HINT_SM100_2SM(N, T_M, T_N, T_K, C_X, C_Y, C_Z) \ +struct Hint##N { \ + using SmArch = cutlass::arch::Sm100; \ + using TileShape = cute::Shape; \ + using ClusterShape = cute::Shape; \ + using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecialized2Sm; \ + using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecialized2SmSm100; \ +} + +// Type B: TmaWarpSpecialized1Sm + KernelTmaWarpSpecialized1SmSm100 +#define DEFINE_HINT_SM100_1SM(N, T_M, T_N, T_K, C_X, C_Y, C_Z) \ +struct Hint##N { \ + using SmArch = cutlass::arch::Sm100; \ + using TileShape = cute::Shape; \ + using ClusterShape = cute::Shape; \ + using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecialized1Sm; \ + using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecialized1SmSm100; \ +} + +// Type C: EpilogueScheduleAuto + KernelTmaWarpSpecialized2SmSm100 +#define DEFINE_HINT_SM100_AUTO_2SM(N, T_M, T_N, T_K, C_X, C_Y, C_Z) \ +struct Hint##N { \ + using SmArch = cutlass::arch::Sm100; \ + using TileShape = cute::Shape; \ + using ClusterShape = cute::Shape; \ + using EpilogueSchedule = cutlass::epilogue::collective::EpilogueScheduleAuto; \ + using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecialized2SmSm100; \ +} + +// Type D: EpilogueScheduleAuto + KernelTmaWarpSpecialized1SmSm100 +#define DEFINE_HINT_SM100_AUTO_1SM(N, T_M, T_N, T_K, C_X, C_Y, C_Z) \ +struct Hint##N { \ + using SmArch = cutlass::arch::Sm100; \ + using TileShape = cute::Shape; \ + using ClusterShape = cute::Shape; \ + using EpilogueSchedule = cutlass::epilogue::collective::EpilogueScheduleAuto; \ + using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecialized1SmSm100; \ +} + +// Hints 38-51: TmaWarpSpecialized2Sm + KernelTmaWarpSpecialized2SmSm100 +// N T_M T_N T_K C_X C_Y C_Z +DEFINE_HINT_SM100_2SM( 38, _128, _128, _64, int, int, _1); +DEFINE_HINT_SM100_2SM( 39, _128, _128, _64, cute::_2, cute::_1, _1); +DEFINE_HINT_SM100_2SM( 40, _128, _128, _64, cute::_2, cute::_2, _1); +DEFINE_HINT_SM100_2SM( 41, _128, _128, _64, cute::_4, cute::_1, _1); +DEFINE_HINT_SM100_2SM( 42, _128, _128, _64, cute::_2, cute::_4, _1); +DEFINE_HINT_SM100_2SM( 43, _128, _128, _64, cute::_4, cute::_2, _1); +DEFINE_HINT_SM100_2SM( 44, _128, _128, _64, cute::_4, cute::_4, _1); +DEFINE_HINT_SM100_2SM( 45, _128, _256, _64, int, int, _1); +DEFINE_HINT_SM100_2SM( 46, _128, _256, _64, cute::_2, cute::_1, _1); +DEFINE_HINT_SM100_2SM( 47, _128, _256, _64, cute::_2, cute::_2, _1); +DEFINE_HINT_SM100_2SM( 48, _128, _256, _64, cute::_4, cute::_1, _1); +DEFINE_HINT_SM100_2SM( 49, _128, _256, _64, cute::_2, cute::_4, _1); +DEFINE_HINT_SM100_2SM( 50, _128, _256, _64, cute::_4, cute::_2, _1); +DEFINE_HINT_SM100_2SM( 51, _128, _256, _64, cute::_4, cute::_4, _1); + +// Hints 52-66: TmaWarpSpecialized1Sm + KernelTmaWarpSpecialized1SmSm100 +// N T_M T_N T_K C_X C_Y C_Z +DEFINE_HINT_SM100_1SM( 52, _64, _128, _64, int, int, _1); +DEFINE_HINT_SM100_1SM( 53, _64, _128, _64, cute::_1, cute::_1, _1); +DEFINE_HINT_SM100_1SM( 54, _64, _128, _64, cute::_1, cute::_2, _1); +DEFINE_HINT_SM100_1SM( 55, _64, _128, _64, cute::_1, cute::_4, _1); +DEFINE_HINT_SM100_1SM( 56, _64, _128, _64, cute::_4, cute::_4, _1); +DEFINE_HINT_SM100_1SM( 57, _128, _128, _64, int, int, _1); +DEFINE_HINT_SM100_1SM( 58, _128, _128, _64, cute::_1, cute::_1, _1); +DEFINE_HINT_SM100_1SM( 59, _128, _128, _64, cute::_1, cute::_2, _1); +DEFINE_HINT_SM100_1SM( 60, _128, _128, _64, cute::_1, cute::_4, _1); +DEFINE_HINT_SM100_1SM( 61, _128, _128, _64, cute::_4, cute::_4, _1); +DEFINE_HINT_SM100_1SM( 62, _128, _256, _64, int, int, _1); +DEFINE_HINT_SM100_1SM( 63, _128, _256, _64, cute::_1, cute::_1, _1); +DEFINE_HINT_SM100_1SM( 64, _128, _256, _64, cute::_1, cute::_2, _1); +DEFINE_HINT_SM100_1SM( 65, _128, _256, _64, cute::_1, cute::_4, _1); +DEFINE_HINT_SM100_1SM( 66, _128, _256, _64, cute::_4, cute::_4, _1); + +// Hints 67-80: EpilogueScheduleAuto + KernelTmaWarpSpecialized2SmSm100 +// N T_M T_N T_K C_X C_Y C_Z +DEFINE_HINT_SM100_AUTO_2SM( 67, _256, _128, _64, int, int, _1); +DEFINE_HINT_SM100_AUTO_2SM( 68, _256, _128, _64, cute::_2, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_2SM( 69, _256, _128, _64, cute::_2, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_2SM( 70, _256, _128, _64, cute::_4, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_2SM( 71, _256, _128, _64, cute::_2, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_2SM( 72, _256, _128, _64, cute::_4, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_2SM( 73, _256, _128, _64, cute::_4, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_2SM( 74, _256, _256, _64, int, int, _1); +DEFINE_HINT_SM100_AUTO_2SM( 75, _256, _256, _64, cute::_2, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_2SM( 76, _256, _256, _64, cute::_2, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_2SM( 77, _256, _256, _64, cute::_4, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_2SM( 78, _256, _256, _64, cute::_2, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_2SM( 79, _256, _256, _64, cute::_4, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_2SM( 80, _256, _256, _64, cute::_4, cute::_4, _1); + +// Hints 81-95: EpilogueScheduleAuto + KernelTmaWarpSpecialized1SmSm100 +// N T_M T_N T_K C_X C_Y C_Z +DEFINE_HINT_SM100_AUTO_1SM( 81, _64, _128, _64, int, int, _1); +DEFINE_HINT_SM100_AUTO_1SM( 82, _64, _128, _64, cute::_1, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_1SM( 83, _64, _128, _64, cute::_1, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_1SM( 84, _64, _128, _64, cute::_1, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_1SM( 85, _64, _128, _64, cute::_4, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_1SM( 86, _128, _128, _64, int, int, _1); +DEFINE_HINT_SM100_AUTO_1SM( 87, _128, _128, _64, cute::_1, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_1SM( 88, _128, _128, _64, cute::_1, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_1SM( 89, _128, _128, _64, cute::_1, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_1SM( 90, _128, _128, _64, cute::_4, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_1SM( 91, _128, _256, _64, int, int, _1); +DEFINE_HINT_SM100_AUTO_1SM( 92, _128, _256, _64, cute::_1, cute::_1, _1); +DEFINE_HINT_SM100_AUTO_1SM( 93, _128, _256, _64, cute::_1, cute::_2, _1); +DEFINE_HINT_SM100_AUTO_1SM( 94, _128, _256, _64, cute::_1, cute::_4, _1); +DEFINE_HINT_SM100_AUTO_1SM( 95, _128, _256, _64, cute::_4, cute::_4, _1); +// clang-format on diff --git a/src/layers/extensions/inference/cuda_check.h b/src/layers/extensions/inference/cuda_check.h new file mode 100644 index 0000000..4687b5d --- /dev/null +++ b/src/layers/extensions/inference/cuda_check.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +#define CUDA_CHECK(expr) \ + do { \ + cudaError_t err = (expr); \ + if (err != cudaSuccess) { \ + throw std::runtime_error(std::string("CUDA error: ") + cudaGetErrorString(err) \ + + " at " + __FILE__ + ":" + std::to_string(__LINE__)); \ + } \ + } while (0) diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias.cu new file mode 100644 index 0000000..bf84e2a --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias.cu @@ -0,0 +1,540 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_NAME = "HINT_MAP_BIAS"; +std::unordered_map HINT_MAP_BIAS = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 20, 12, 512, 128, 0, 0), 28 }, + { conv_key(80, 20, 12, 1024, 128, 0, 0), 17 }, + { conv_key(80, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(80, 26, 15, 256, 128, 0, 0), 19 }, + { conv_key(80, 26, 15, 256, 512, 0, 0), 8 }, + { conv_key(80, 26, 15, 256, 768, 0, 0), 8 }, + { conv_key(80, 26, 15, 384, 384, 0, 0), 8 }, + { conv_key(80, 26, 15, 512, 256, 0, 0), 8 }, + { conv_key(80, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(80, 26, 15, 768, 768, 0, 0), 8 }, + { conv_key(80, 28, 16, 128, 256, 0, 0), 19 }, + { conv_key(80, 28, 16, 256, 128, 0, 0), 29 }, + { conv_key(80, 28, 16, 512, 256, 0, 0), 8 }, + { conv_key(80, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(80, 30, 17, 512, 128, 0, 0), 7 }, + { conv_key(80, 30, 17, 1024, 128, 0, 0), 18 }, + { conv_key(80, 40, 24, 512, 128, 0, 0), 17 }, + { conv_key(80, 40, 24, 1024, 256, 0, 0), 14 }, + { conv_key(80, 52, 30, 128, 256, 0, 0), 19 }, + { conv_key(80, 52, 30, 192, 256, 0, 0), 19 }, + { conv_key(80, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(80, 52, 30, 256, 128, 0, 0), 17 }, + { conv_key(80, 52, 30, 256, 192, 0, 0), 19 }, + { conv_key(80, 52, 30, 256, 256, 0, 0), 19 }, + { conv_key(80, 52, 30, 256, 448, 0, 0), 8 }, + { conv_key(80, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(80, 52, 30, 256, 768, 0, 0), 8 }, + { conv_key(80, 52, 30, 384, 192, 0, 0), 29 }, + { conv_key(80, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 192, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(80, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 1024, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 1536, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 2048, 0, 0), 29 }, + { conv_key(80, 52, 30, 768, 768, 0, 0), 14 }, + { conv_key(80, 52, 32, 128, 256, 0, 0), 19 }, + { conv_key(80, 52, 32, 256, 128, 0, 0), 28 }, + { conv_key(80, 52, 32, 512, 256, 0, 0), 29 }, + { conv_key(80, 52, 32, 512, 512, 0, 0), 29 }, + { conv_key(80, 60, 34, 512, 128, 0, 0), 14 }, + { conv_key(80, 60, 34, 1024, 128, 0, 0), 1 }, + { conv_key(80, 60, 34, 1024, 256, 0, 0), 14 }, + { conv_key(80, 80, 45, 128, 256, 0, 0), 29 }, + { conv_key(80, 80, 45, 256, 128, 0, 0), 14 }, + { conv_key(80, 80, 45, 256, 512, 0, 0), 14 }, + { conv_key(80, 80, 45, 256, 768, 0, 0), 14 }, + { conv_key(80, 80, 45, 384, 384, 0, 0), 27 }, + { conv_key(80, 80, 45, 512, 256, 0, 0), 14 }, + { conv_key(80, 80, 45, 512, 512, 0, 0), 29 }, + { conv_key(80, 80, 45, 768, 768, 0, 0), 9 }, + { conv_key(80, 80, 45, 1536, 256, 0, 0), 14 }, + { conv_key(80, 80, 48, 128, 256, 0, 0), 29 }, + { conv_key(80, 80, 48, 256, 128, 0, 0), 14 }, + { conv_key(80, 80, 48, 512, 256, 0, 0), 14 }, + { conv_key(80, 80, 48, 512, 512, 0, 0), 9 }, + { conv_key(80, 104, 60, 192, 256, 0, 0), 14 }, + { conv_key(80, 104, 60, 192, 384, 0, 0), 14 }, + { conv_key(80, 104, 60, 256, 192, 0, 0), 14 }, + { conv_key(80, 104, 60, 256, 256, 0, 0), 14 }, + { conv_key(80, 104, 60, 256, 448, 0, 0), 14 }, + { conv_key(80, 104, 60, 256, 512, 0, 0), 14 }, + { conv_key(80, 104, 60, 384, 192, 0, 0), 14 }, + { conv_key(80, 104, 60, 512, 192, 0, 0), 14 }, + { conv_key(80, 104, 60, 512, 512, 0, 0), 14 }, + { conv_key(80, 104, 60, 512, 1024, 0, 0), 14 }, + { conv_key(80, 104, 60, 512, 1536, 0, 0), 9 }, + { conv_key(80, 104, 60, 512, 2048, 0, 0), 9 }, + { conv_key(80, 120, 68, 128, 256, 0, 0), 16 }, + { conv_key(80, 120, 68, 256, 128, 0, 0), 14 }, + { conv_key(80, 120, 68, 256, 512, 0, 0), 9 }, + { conv_key(80, 120, 68, 256, 768, 0, 0), 21 }, + { conv_key(80, 120, 68, 384, 384, 0, 0), 11 }, + { conv_key(80, 120, 68, 512, 128, 0, 0), 14 }, + { conv_key(80, 120, 68, 512, 256, 0, 0), 14 }, + { conv_key(80, 120, 68, 512, 512, 0, 0), 14 }, + { conv_key(80, 120, 68, 768, 768, 0, 0), 9 }, + { conv_key(80, 120, 68, 1024, 256, 0, 0), 14 }, + { conv_key(80, 120, 68, 1536, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 192, 256, 0, 0), 11 }, + { conv_key(80, 160, 90, 192, 384, 0, 0), 11 }, + { conv_key(80, 160, 90, 256, 192, 0, 0), 14 }, + { conv_key(80, 160, 90, 256, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 256, 448, 0, 0), 14 }, + { conv_key(80, 160, 90, 256, 512, 0, 0), 14 }, + { conv_key(80, 160, 90, 384, 192, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 192, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 512, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 1024, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 1536, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 2048, 0, 0), 14 }, + { conv_key(80, 240, 135, 128, 256, 0, 0), 2 }, + { conv_key(80, 240, 135, 256, 128, 0, 0), 14 }, + { conv_key(80, 240, 135, 256, 512, 0, 0), 14 }, + { conv_key(80, 240, 135, 256, 768, 0, 0), 14 }, + { conv_key(80, 240, 135, 384, 384, 0, 0), 14 }, + { conv_key(80, 240, 135, 512, 256, 0, 0), 14 }, + { conv_key(80, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(80, 240, 135, 768, 768, 0, 0), 14 }, + { conv_key(80, 240, 135, 1536, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 128, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 192, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 192, 384, 0, 0), 11 }, + { conv_key(80, 240, 136, 256, 128, 0, 0), 14 }, + { conv_key(80, 240, 136, 256, 192, 0, 0), 14 }, + { conv_key(80, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 256, 448, 0, 0), 14 }, + { conv_key(80, 240, 136, 256, 512, 0, 0), 14 }, + { conv_key(80, 240, 136, 384, 192, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 192, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 512, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 1024, 0, 0), 9 }, + { conv_key(80, 240, 136, 512, 1536, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 2048, 0, 0), 9 }, + { conv_key(80, 480, 270, 192, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 192, 384, 0, 0), 11 }, + { conv_key(80, 480, 270, 256, 192, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 448, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 512, 0, 0), 14 }, + { conv_key(80, 480, 270, 384, 192, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 192, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 512, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 1024, 0, 0), 20 }, + { conv_key(80, 480, 270, 512, 1536, 0, 0), 20 }, + { conv_key(80, 480, 270, 512, 2048, 0, 0), 20 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 20, 12, 512, 128, 0, 0), 19 }, + { conv_key(89, 20, 12, 1024, 128, 0, 0), 18 }, + { conv_key(89, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(89, 26, 15, 256, 128, 0, 0), 7 }, + { conv_key(89, 26, 15, 256, 512, 0, 0), 8 }, + { conv_key(89, 26, 15, 256, 768, 0, 0), 8 }, + { conv_key(89, 26, 15, 384, 384, 0, 0), 19 }, + { conv_key(89, 26, 15, 512, 256, 0, 0), 19 }, + { conv_key(89, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(89, 26, 15, 768, 768, 0, 0), 8 }, + { conv_key(89, 28, 16, 128, 256, 0, 0), 19 }, + { conv_key(89, 28, 16, 256, 128, 0, 0), 8 }, + { conv_key(89, 28, 16, 512, 256, 0, 0), 8 }, + { conv_key(89, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(89, 30, 17, 512, 128, 0, 0), 19 }, + { conv_key(89, 30, 17, 1024, 128, 0, 0), 19 }, + { conv_key(89, 40, 24, 512, 128, 0, 0), 18 }, + { conv_key(89, 40, 24, 1024, 256, 0, 0), 29 }, + { conv_key(89, 52, 30, 128, 256, 0, 0), 8 }, + { conv_key(89, 52, 30, 192, 256, 0, 0), 8 }, + { conv_key(89, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 128, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 192, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 256, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 448, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 768, 0, 0), 8 }, + { conv_key(89, 52, 30, 384, 192, 0, 0), 18 }, + { conv_key(89, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(89, 52, 30, 512, 192, 0, 0), 29 }, + { conv_key(89, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(89, 52, 30, 512, 512, 0, 0), 18 }, + { conv_key(89, 52, 30, 512, 1024, 0, 0), 29 }, + { conv_key(89, 52, 30, 512, 1536, 0, 0), 28 }, + { conv_key(89, 52, 30, 512, 2048, 0, 0), 28 }, + { conv_key(89, 52, 30, 768, 768, 0, 0), 14 }, + { conv_key(89, 52, 32, 128, 256, 0, 0), 19 }, + { conv_key(89, 52, 32, 256, 128, 0, 0), 17 }, + { conv_key(89, 52, 32, 512, 256, 0, 0), 18 }, + { conv_key(89, 52, 32, 512, 512, 0, 0), 18 }, + { conv_key(89, 60, 34, 512, 128, 0, 0), 17 }, + { conv_key(89, 60, 34, 1024, 128, 0, 0), 14 }, + { conv_key(89, 60, 34, 1024, 256, 0, 0), 14 }, + { conv_key(89, 80, 45, 128, 256, 0, 0), 8 }, + { conv_key(89, 80, 45, 256, 128, 0, 0), 7 }, + { conv_key(89, 80, 45, 256, 512, 0, 0), 29 }, + { conv_key(89, 80, 45, 256, 768, 0, 0), 17 }, + { conv_key(89, 80, 45, 384, 384, 0, 0), 14 }, + { conv_key(89, 80, 45, 512, 256, 0, 0), 14 }, + { conv_key(89, 80, 45, 512, 512, 0, 0), 14 }, + { conv_key(89, 80, 45, 768, 768, 0, 0), 14 }, + { conv_key(89, 80, 45, 1536, 256, 0, 0), 14 }, + { conv_key(89, 80, 48, 128, 256, 0, 0), 17 }, + { conv_key(89, 80, 48, 256, 128, 0, 0), 7 }, + { conv_key(89, 80, 48, 512, 256, 0, 0), 14 }, + { conv_key(89, 80, 48, 512, 512, 0, 0), 15 }, + { conv_key(89, 104, 60, 192, 256, 0, 0), 11 }, + { conv_key(89, 104, 60, 192, 384, 0, 0), 11 }, + { conv_key(89, 104, 60, 256, 192, 0, 0), 14 }, + { conv_key(89, 104, 60, 256, 256, 0, 0), 14 }, + { conv_key(89, 104, 60, 256, 448, 0, 0), 14 }, + { conv_key(89, 104, 60, 256, 512, 0, 0), 14 }, + { conv_key(89, 104, 60, 384, 192, 0, 0), 5 }, + { conv_key(89, 104, 60, 512, 192, 0, 0), 14 }, + { conv_key(89, 104, 60, 512, 512, 0, 0), 14 }, + { conv_key(89, 104, 60, 512, 1024, 0, 0), 14 }, + { conv_key(89, 104, 60, 512, 1536, 0, 0), 9 }, + { conv_key(89, 104, 60, 512, 2048, 0, 0), 9 }, + { conv_key(89, 120, 68, 128, 256, 0, 0), 17 }, + { conv_key(89, 120, 68, 256, 128, 0, 0), 14 }, + { conv_key(89, 120, 68, 256, 512, 0, 0), 14 }, + { conv_key(89, 120, 68, 256, 768, 0, 0), 15 }, + { conv_key(89, 120, 68, 384, 384, 0, 0), 14 }, + { conv_key(89, 120, 68, 512, 128, 0, 0), 14 }, + { conv_key(89, 120, 68, 512, 256, 0, 0), 9 }, + { conv_key(89, 120, 68, 512, 512, 0, 0), 9 }, + { conv_key(89, 120, 68, 768, 768, 0, 0), 14 }, + { conv_key(89, 120, 68, 1024, 256, 0, 0), 9 }, + { conv_key(89, 120, 68, 1536, 256, 0, 0), 9 }, + { conv_key(89, 160, 90, 192, 256, 0, 0), 6 }, + { conv_key(89, 160, 90, 192, 384, 0, 0), 14 }, + { conv_key(89, 160, 90, 256, 192, 0, 0), 14 }, + { conv_key(89, 160, 90, 256, 256, 0, 0), 2 }, + { conv_key(89, 160, 90, 256, 448, 0, 0), 14 }, + { conv_key(89, 160, 90, 256, 512, 0, 0), 9 }, + { conv_key(89, 160, 90, 384, 192, 0, 0), 2 }, + { conv_key(89, 160, 90, 512, 192, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 512, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 1024, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 1536, 0, 0), 10 }, + { conv_key(89, 160, 90, 512, 2048, 0, 0), 10 }, + { conv_key(89, 240, 135, 128, 256, 0, 0), 9 }, + { conv_key(89, 240, 135, 256, 128, 0, 0), 14 }, + { conv_key(89, 240, 135, 256, 512, 0, 0), 14 }, + { conv_key(89, 240, 135, 256, 768, 0, 0), 9 }, + { conv_key(89, 240, 135, 384, 384, 0, 0), 14 }, + { conv_key(89, 240, 135, 512, 256, 0, 0), 2 }, + { conv_key(89, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(89, 240, 135, 768, 768, 0, 0), 14 }, + { conv_key(89, 240, 135, 1536, 256, 0, 0), 14 }, + { conv_key(89, 240, 136, 128, 256, 0, 0), 9 }, + { conv_key(89, 240, 136, 192, 256, 0, 0), 12 }, + { conv_key(89, 240, 136, 192, 384, 0, 0), 14 }, + { conv_key(89, 240, 136, 256, 128, 0, 0), 14 }, + { conv_key(89, 240, 136, 256, 192, 0, 0), 14 }, + { conv_key(89, 240, 136, 256, 256, 0, 0), 9 }, + { conv_key(89, 240, 136, 256, 448, 0, 0), 14 }, + { conv_key(89, 240, 136, 256, 512, 0, 0), 9 }, + { conv_key(89, 240, 136, 384, 192, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 192, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 512, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 1024, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 1536, 0, 0), 9 }, + { conv_key(89, 240, 136, 512, 2048, 0, 0), 10 }, + { conv_key(89, 480, 270, 192, 256, 0, 0), 17 }, + { conv_key(89, 480, 270, 192, 384, 0, 0), 17 }, + { conv_key(89, 480, 270, 256, 192, 0, 0), 16 }, + { conv_key(89, 480, 270, 256, 256, 0, 0), 1 }, + { conv_key(89, 480, 270, 256, 448, 0, 0), 1 }, + { conv_key(89, 480, 270, 256, 512, 0, 0), 1 }, + { conv_key(89, 480, 270, 384, 192, 0, 0), 16 }, + { conv_key(89, 480, 270, 512, 192, 0, 0), 16 }, + { conv_key(89, 480, 270, 512, 512, 0, 0), 9 }, + { conv_key(89, 480, 270, 512, 1024, 0, 0), 9 }, + { conv_key(89, 480, 270, 512, 1536, 0, 0), 9 }, + { conv_key(89, 480, 270, 512, 2048, 0, 0), 9 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 20, 12, 512, 128, 0, 0), 8 }, + { conv_key(90, 20, 12, 1024, 128, 0, 0), 8 }, + { conv_key(90, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(90, 26, 15, 256, 128, 0, 0), 8 }, + { conv_key(90, 26, 15, 256, 512, 0, 0), 8 }, + { conv_key(90, 26, 15, 256, 768, 0, 0), 8 }, + { conv_key(90, 26, 15, 384, 384, 0, 0), 8 }, + { conv_key(90, 26, 15, 512, 256, 0, 0), 8 }, + { conv_key(90, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(90, 26, 15, 768, 768, 0, 0), 8 }, + { conv_key(90, 28, 16, 128, 256, 0, 0), 8 }, + { conv_key(90, 28, 16, 256, 128, 0, 0), 8 }, + { conv_key(90, 28, 16, 512, 256, 0, 0), 8 }, + { conv_key(90, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(90, 30, 17, 512, 128, 0, 0), 8 }, + { conv_key(90, 30, 17, 1024, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 512, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 1024, 256, 0, 0), 29 }, + { conv_key(90, 52, 30, 128, 256, 0, 0), 8 }, + { conv_key(90, 52, 30, 192, 256, 0, 0), 8 }, + { conv_key(90, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 128, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 192, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 256, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 448, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 768, 0, 0), 8 }, + { conv_key(90, 52, 30, 384, 192, 0, 0), 29 }, + { conv_key(90, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 192, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 256, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 1024, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 1536, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 2048, 0, 0), 29 }, + { conv_key(90, 52, 30, 768, 768, 0, 0), 30 }, + { conv_key(90, 52, 32, 128, 256, 0, 0), 8 }, + { conv_key(90, 52, 32, 256, 128, 0, 0), 8 }, + { conv_key(90, 52, 32, 512, 256, 0, 0), 29 }, + { conv_key(90, 52, 32, 512, 512, 0, 0), 29 }, + { conv_key(90, 60, 34, 512, 128, 0, 0), 29 }, + { conv_key(90, 60, 34, 1024, 128, 0, 0), 29 }, + { conv_key(90, 60, 34, 1024, 256, 0, 0), 14 }, + { conv_key(90, 80, 45, 128, 256, 0, 0), 8 }, + { conv_key(90, 80, 45, 256, 128, 0, 0), 29 }, + { conv_key(90, 80, 45, 256, 512, 0, 0), 29 }, + { conv_key(90, 80, 45, 256, 768, 0, 0), 29 }, + { conv_key(90, 80, 45, 384, 384, 0, 0), 27 }, + { conv_key(90, 80, 45, 512, 256, 0, 0), 14 }, + { conv_key(90, 80, 45, 512, 512, 0, 0), 30 }, + { conv_key(90, 80, 45, 768, 768, 0, 0), 33 }, + { conv_key(90, 80, 45, 1536, 256, 0, 0), 46 }, + { conv_key(90, 80, 48, 128, 256, 0, 0), 8 }, + { conv_key(90, 80, 48, 256, 128, 0, 0), 29 }, + { conv_key(90, 80, 48, 512, 256, 0, 0), 14 }, + { conv_key(90, 80, 48, 512, 512, 0, 0), 30 }, + { conv_key(90, 104, 60, 192, 256, 0, 0), 30 }, + { conv_key(90, 104, 60, 192, 384, 0, 0), 30 }, + { conv_key(90, 104, 60, 256, 192, 0, 0), 30 }, + { conv_key(90, 104, 60, 256, 256, 0, 0), 30 }, + { conv_key(90, 104, 60, 256, 448, 0, 0), 30 }, + { conv_key(90, 104, 60, 256, 512, 0, 0), 30 }, + { conv_key(90, 104, 60, 384, 192, 0, 0), 32 }, + { conv_key(90, 104, 60, 512, 192, 0, 0), 32 }, + { conv_key(90, 104, 60, 512, 512, 0, 0), 32 }, + { conv_key(90, 104, 60, 512, 1024, 0, 0), 32 }, + { conv_key(90, 104, 60, 512, 1536, 0, 0), 32 }, + { conv_key(90, 104, 60, 512, 2048, 0, 0), 32 }, + { conv_key(90, 120, 68, 128, 256, 0, 0), 29 }, + { conv_key(90, 120, 68, 256, 128, 0, 0), 29 }, + { conv_key(90, 120, 68, 256, 512, 0, 0), 30 }, + { conv_key(90, 120, 68, 256, 768, 0, 0), 30 }, + { conv_key(90, 120, 68, 384, 384, 0, 0), 32 }, + { conv_key(90, 120, 68, 512, 128, 0, 0), 32 }, + { conv_key(90, 120, 68, 512, 256, 0, 0), 32 }, + { conv_key(90, 120, 68, 512, 512, 0, 0), 32 }, + { conv_key(90, 120, 68, 768, 768, 0, 0), 30 }, + { conv_key(90, 120, 68, 1024, 256, 0, 0), 36 }, + { conv_key(90, 120, 68, 1536, 256, 0, 0), 46 }, + { conv_key(90, 160, 90, 192, 256, 0, 0), 28 }, + { conv_key(90, 160, 90, 192, 384, 0, 0), 34 }, + { conv_key(90, 160, 90, 256, 192, 0, 0), 34 }, + { conv_key(90, 160, 90, 256, 256, 0, 0), 34 }, + { conv_key(90, 160, 90, 256, 448, 0, 0), 34 }, + { conv_key(90, 160, 90, 256, 512, 0, 0), 34 }, + { conv_key(90, 160, 90, 384, 192, 0, 0), 14 }, + { conv_key(90, 160, 90, 512, 192, 0, 0), 36 }, + { conv_key(90, 160, 90, 512, 512, 0, 0), 36 }, + { conv_key(90, 160, 90, 512, 1024, 0, 0), 36 }, + { conv_key(90, 160, 90, 512, 1536, 0, 0), 36 }, + { conv_key(90, 160, 90, 512, 2048, 0, 0), 37 }, + { conv_key(90, 240, 135, 128, 256, 0, 0), 35 }, + { conv_key(90, 240, 135, 256, 128, 0, 0), 37 }, + { conv_key(90, 240, 135, 256, 512, 0, 0), 37 }, + { conv_key(90, 240, 135, 256, 768, 0, 0), 33 }, + { conv_key(90, 240, 135, 384, 384, 0, 0), 35 }, + { conv_key(90, 240, 135, 512, 256, 0, 0), 36 }, + { conv_key(90, 240, 135, 512, 512, 0, 0), 36 }, + { conv_key(90, 240, 135, 768, 768, 0, 0), 37 }, + { conv_key(90, 240, 135, 1536, 256, 0, 0), 41 }, + { conv_key(90, 240, 136, 128, 256, 0, 0), 35 }, + { conv_key(90, 240, 136, 192, 256, 0, 0), 11 }, + { conv_key(90, 240, 136, 192, 384, 0, 0), 37 }, + { conv_key(90, 240, 136, 256, 128, 0, 0), 34 }, + { conv_key(90, 240, 136, 256, 192, 0, 0), 37 }, + { conv_key(90, 240, 136, 256, 256, 0, 0), 37 }, + { conv_key(90, 240, 136, 256, 448, 0, 0), 33 }, + { conv_key(90, 240, 136, 256, 512, 0, 0), 37 }, + { conv_key(90, 240, 136, 384, 192, 0, 0), 35 }, + { conv_key(90, 240, 136, 512, 192, 0, 0), 36 }, + { conv_key(90, 240, 136, 512, 256, 0, 0), 36 }, + { conv_key(90, 240, 136, 512, 512, 0, 0), 36 }, + { conv_key(90, 240, 136, 512, 1024, 0, 0), 36 }, + { conv_key(90, 240, 136, 512, 1536, 0, 0), 36 }, + { conv_key(90, 240, 136, 512, 2048, 0, 0), 37 }, + { conv_key(90, 480, 270, 192, 256, 0, 0), 37 }, + { conv_key(90, 480, 270, 192, 384, 0, 0), 37 }, + { conv_key(90, 480, 270, 256, 192, 0, 0), 37 }, + { conv_key(90, 480, 270, 256, 256, 0, 0), 33 }, + { conv_key(90, 480, 270, 256, 448, 0, 0), 33 }, + { conv_key(90, 480, 270, 256, 512, 0, 0), 37 }, + { conv_key(90, 480, 270, 384, 192, 0, 0), 35 }, + { conv_key(90, 480, 270, 512, 192, 0, 0), 36 }, + { conv_key(90, 480, 270, 512, 512, 0, 0), 36 }, + { conv_key(90, 480, 270, 512, 1024, 0, 0), 32 }, + { conv_key(90, 480, 270, 512, 1536, 0, 0), 36 }, + { conv_key(90, 480, 270, 512, 2048, 0, 0), 37 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 20, 12, 512, 128, 0, 0), 8 }, + { conv_key(100, 20, 12, 1024, 128, 0, 0), 8 }, + { conv_key(100, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(100, 26, 15, 256, 128, 0, 0), 26 }, + { conv_key(100, 26, 15, 256, 512, 0, 0), 8 }, + { conv_key(100, 26, 15, 256, 768, 0, 0), 8 }, + { conv_key(100, 26, 15, 384, 384, 0, 0), 19 }, + { conv_key(100, 26, 15, 512, 256, 0, 0), 8 }, + { conv_key(100, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(100, 26, 15, 768, 768, 0, 0), 8 }, + { conv_key(100, 28, 16, 128, 256, 0, 0), 18 }, + { conv_key(100, 28, 16, 256, 128, 0, 0), 18 }, + { conv_key(100, 28, 16, 512, 256, 0, 0), 29 }, + { conv_key(100, 28, 16, 512, 512, 0, 0), 19 }, + { conv_key(100, 30, 17, 512, 128, 0, 0), 8 }, + { conv_key(100, 30, 17, 1024, 128, 0, 0), 82 }, + { conv_key(100, 40, 24, 512, 128, 0, 0), 53 }, + { conv_key(100, 40, 24, 1024, 256, 0, 0), 58 }, + { conv_key(100, 52, 30, 128, 256, 0, 0), 28 }, + { conv_key(100, 52, 30, 192, 256, 0, 0), 7 }, + { conv_key(100, 52, 30, 192, 384, 0, 0), 19 }, + { conv_key(100, 52, 30, 256, 128, 0, 0), 29 }, + { conv_key(100, 52, 30, 256, 192, 0, 0), 8 }, + { conv_key(100, 52, 30, 256, 256, 0, 0), 8 }, + { conv_key(100, 52, 30, 256, 448, 0, 0), 8 }, + { conv_key(100, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(100, 52, 30, 256, 768, 0, 0), 8 }, + { conv_key(100, 52, 30, 384, 192, 0, 0), 25 }, + { conv_key(100, 52, 30, 384, 384, 0, 0), 28 }, + { conv_key(100, 52, 30, 512, 192, 0, 0), 5 }, + { conv_key(100, 52, 30, 512, 256, 0, 0), 17 }, + { conv_key(100, 52, 30, 512, 512, 0, 0), 28 }, + { conv_key(100, 52, 30, 512, 1024, 0, 0), 87 }, + { conv_key(100, 52, 30, 512, 1536, 0, 0), 58 }, + { conv_key(100, 52, 30, 512, 2048, 0, 0), 42 }, + { conv_key(100, 52, 30, 768, 768, 0, 0), 58 }, + { conv_key(100, 52, 32, 128, 256, 0, 0), 28 }, + { conv_key(100, 52, 32, 256, 128, 0, 0), 17 }, + { conv_key(100, 52, 32, 512, 256, 0, 0), 8 }, + { conv_key(100, 52, 32, 512, 512, 0, 0), 28 }, + { conv_key(100, 60, 34, 512, 128, 0, 0), 63 }, + { conv_key(100, 60, 34, 1024, 128, 0, 0), 92 }, + { conv_key(100, 60, 34, 1024, 256, 0, 0), 58 }, + { conv_key(100, 80, 45, 128, 256, 0, 0), 8 }, + { conv_key(100, 80, 45, 256, 128, 0, 0), 7 }, + { conv_key(100, 80, 45, 256, 512, 0, 0), 28 }, + { conv_key(100, 80, 45, 256, 768, 0, 0), 82 }, + { conv_key(100, 80, 45, 384, 384, 0, 0), 63 }, + { conv_key(100, 80, 45, 512, 256, 0, 0), 27 }, + { conv_key(100, 80, 45, 512, 512, 0, 0), 87 }, + { conv_key(100, 80, 45, 768, 768, 0, 0), 68 }, + { conv_key(100, 80, 45, 1536, 256, 0, 0), 46 }, + { conv_key(100, 80, 48, 128, 256, 0, 0), 17 }, + { conv_key(100, 80, 48, 256, 128, 0, 0), 5 }, + { conv_key(100, 80, 48, 512, 256, 0, 0), 27 }, + { conv_key(100, 80, 48, 512, 512, 0, 0), 87 }, + { conv_key(100, 104, 60, 192, 256, 0, 0), 8 }, + { conv_key(100, 104, 60, 192, 384, 0, 0), 8 }, + { conv_key(100, 104, 60, 256, 192, 0, 0), 27 }, + { conv_key(100, 104, 60, 256, 256, 0, 0), 27 }, + { conv_key(100, 104, 60, 256, 448, 0, 0), 87 }, + { conv_key(100, 104, 60, 256, 512, 0, 0), 87 }, + { conv_key(100, 104, 60, 384, 192, 0, 0), 24 }, + { conv_key(100, 104, 60, 512, 192, 0, 0), 29 }, + { conv_key(100, 104, 60, 512, 512, 0, 0), 63 }, + { conv_key(100, 104, 60, 512, 1024, 0, 0), 46 }, + { conv_key(100, 104, 60, 512, 1536, 0, 0), 40 }, + { conv_key(100, 104, 60, 512, 2048, 0, 0), 40 }, + { conv_key(100, 120, 68, 128, 256, 0, 0), 29 }, + { conv_key(100, 120, 68, 256, 128, 0, 0), 13 }, + { conv_key(100, 120, 68, 256, 512, 0, 0), 63 }, + { conv_key(100, 120, 68, 256, 768, 0, 0), 58 }, + { conv_key(100, 120, 68, 384, 384, 0, 0), 59 }, + { conv_key(100, 120, 68, 512, 128, 0, 0), 58 }, + { conv_key(100, 120, 68, 512, 256, 0, 0), 87 }, + { conv_key(100, 120, 68, 512, 512, 0, 0), 68 }, + { conv_key(100, 120, 68, 768, 768, 0, 0), 70 }, + { conv_key(100, 120, 68, 1024, 256, 0, 0), 63 }, + { conv_key(100, 120, 68, 1536, 256, 0, 0), 76 }, + { conv_key(100, 160, 90, 192, 256, 0, 0), 92 }, + { conv_key(100, 160, 90, 192, 384, 0, 0), 63 }, + { conv_key(100, 160, 90, 256, 192, 0, 0), 87 }, + { conv_key(100, 160, 90, 256, 256, 0, 0), 58 }, + { conv_key(100, 160, 90, 256, 448, 0, 0), 69 }, + { conv_key(100, 160, 90, 256, 512, 0, 0), 63 }, + { conv_key(100, 160, 90, 384, 192, 0, 0), 68 }, + { conv_key(100, 160, 90, 512, 192, 0, 0), 63 }, + { conv_key(100, 160, 90, 512, 512, 0, 0), 50 }, + { conv_key(100, 160, 90, 512, 1024, 0, 0), 71 }, + { conv_key(100, 160, 90, 512, 1536, 0, 0), 46 }, + { conv_key(100, 160, 90, 512, 2048, 0, 0), 47 }, + { conv_key(100, 240, 135, 128, 256, 0, 0), 58 }, + { conv_key(100, 240, 135, 256, 128, 0, 0), 92 }, + { conv_key(100, 240, 135, 256, 512, 0, 0), 75 }, + { conv_key(100, 240, 135, 256, 768, 0, 0), 69 }, + { conv_key(100, 240, 135, 384, 384, 0, 0), 77 }, + { conv_key(100, 240, 135, 512, 256, 0, 0), 76 }, + { conv_key(100, 240, 135, 512, 512, 0, 0), 76 }, + { conv_key(100, 240, 135, 768, 768, 0, 0), 77 }, + { conv_key(100, 240, 135, 1536, 256, 0, 0), 75 }, + { conv_key(100, 240, 136, 128, 256, 0, 0), 87 }, + { conv_key(100, 240, 136, 192, 256, 0, 0), 75 }, + { conv_key(100, 240, 136, 192, 384, 0, 0), 75 }, + { conv_key(100, 240, 136, 256, 128, 0, 0), 63 }, + { conv_key(100, 240, 136, 256, 192, 0, 0), 63 }, + { conv_key(100, 240, 136, 256, 256, 0, 0), 63 }, + { conv_key(100, 240, 136, 256, 448, 0, 0), 75 }, + { conv_key(100, 240, 136, 256, 512, 0, 0), 75 }, + { conv_key(100, 240, 136, 384, 192, 0, 0), 76 }, + { conv_key(100, 240, 136, 512, 192, 0, 0), 76 }, + { conv_key(100, 240, 136, 512, 256, 0, 0), 76 }, + { conv_key(100, 240, 136, 512, 512, 0, 0), 76 }, + { conv_key(100, 240, 136, 512, 1024, 0, 0), 68 }, + { conv_key(100, 240, 136, 512, 1536, 0, 0), 75 }, + { conv_key(100, 240, 136, 512, 2048, 0, 0), 68 }, + { conv_key(100, 480, 270, 192, 256, 0, 0), 75 }, + { conv_key(100, 480, 270, 192, 384, 0, 0), 75 }, + { conv_key(100, 480, 270, 256, 192, 0, 0), 75 }, + { conv_key(100, 480, 270, 256, 256, 0, 0), 75 }, + { conv_key(100, 480, 270, 256, 448, 0, 0), 75 }, + { conv_key(100, 480, 270, 256, 512, 0, 0), 75 }, + { conv_key(100, 480, 270, 384, 192, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 192, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 512, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 1024, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 1536, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 2048, 0, 0), 68 }, +#endif +}; + +at::Tensor conv1x1_bias(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + return out + bias.reshape({ 1, -1, 1, 1 }); + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass(out_buf, feature, weight, bias); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS, HINT_MAP_BIAS_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut.cu new file mode 100644 index 0000000..9d706e8 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut.cu @@ -0,0 +1,247 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_SHORTCUT_NAME = "HINT_MAP_BIAS_SHORTCUT"; +std::unordered_map HINT_MAP_BIAS_SHORTCUT = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 7, 4, 128, 64, 0, 0), 19 }, { conv_key(80, 7, 4, 128, 128, 0, 0), 8 }, + { conv_key(80, 13, 8, 128, 64, 0, 0), 8 }, { conv_key(80, 13, 8, 128, 128, 0, 0), 19 }, + { conv_key(80, 14, 8, 128, 64, 0, 0), 8 }, { conv_key(80, 14, 8, 128, 128, 0, 0), 7 }, + { conv_key(80, 14, 8, 256, 256, 0, 0), 8 }, { conv_key(80, 20, 12, 128, 64, 0, 0), 8 }, + { conv_key(80, 20, 12, 128, 128, 0, 0), 19 }, { conv_key(80, 26, 15, 256, 128, 0, 0), 19 }, + { conv_key(80, 26, 15, 384, 192, 0, 0), 8 }, { conv_key(80, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(80, 26, 15, 768, 768, 0, 0), 8 }, { conv_key(80, 26, 16, 128, 64, 0, 0), 8 }, + { conv_key(80, 26, 16, 128, 128, 0, 0), 8 }, { conv_key(80, 26, 16, 256, 256, 0, 0), 8 }, + { conv_key(80, 28, 16, 128, 64, 0, 0), 5 }, { conv_key(80, 28, 16, 128, 128, 0, 0), 29 }, + { conv_key(80, 28, 16, 256, 256, 0, 0), 8 }, { conv_key(80, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(80, 30, 17, 128, 64, 0, 0), 8 }, { conv_key(80, 30, 17, 128, 128, 0, 0), 19 }, + { conv_key(80, 40, 24, 128, 64, 0, 0), 19 }, { conv_key(80, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(80, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(80, 52, 30, 192, 192, 0, 0), 19 }, + { conv_key(80, 52, 30, 256, 128, 0, 0), 19 }, { conv_key(80, 52, 30, 256, 256, 0, 0), 19 }, + { conv_key(80, 52, 30, 384, 192, 0, 0), 29 }, { conv_key(80, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 256, 0, 0), 18 }, { conv_key(80, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(80, 52, 30, 768, 768, 0, 0), 14 }, { conv_key(80, 52, 32, 128, 64, 0, 0), 19 }, + { conv_key(80, 52, 32, 128, 128, 0, 0), 8 }, { conv_key(80, 52, 32, 256, 256, 0, 0), 8 }, + { conv_key(80, 52, 32, 512, 512, 0, 0), 29 }, { conv_key(80, 60, 34, 128, 64, 0, 0), 7 }, + { conv_key(80, 60, 34, 128, 128, 0, 0), 19 }, { conv_key(80, 60, 34, 256, 256, 0, 0), 29 }, + { conv_key(80, 80, 45, 256, 128, 0, 0), 14 }, { conv_key(80, 80, 45, 384, 192, 0, 0), 24 }, + { conv_key(80, 80, 45, 512, 512, 0, 0), 29 }, { conv_key(80, 80, 45, 768, 768, 0, 0), 9 }, + { conv_key(80, 80, 48, 128, 64, 0, 0), 29 }, { conv_key(80, 80, 48, 128, 128, 0, 0), 18 }, + { conv_key(80, 80, 48, 256, 256, 0, 0), 14 }, { conv_key(80, 80, 48, 512, 512, 0, 0), 29 }, + { conv_key(80, 104, 60, 192, 192, 0, 0), 11 }, { conv_key(80, 104, 60, 256, 128, 0, 0), 14 }, + { conv_key(80, 104, 60, 256, 256, 0, 0), 14 }, { conv_key(80, 104, 60, 384, 384, 0, 0), 14 }, + { conv_key(80, 104, 60, 512, 256, 0, 0), 14 }, { conv_key(80, 104, 60, 512, 512, 0, 0), 10 }, + { conv_key(80, 120, 68, 128, 64, 0, 0), 7 }, { conv_key(80, 120, 68, 128, 128, 0, 0), 14 }, + { conv_key(80, 120, 68, 256, 128, 0, 0), 5 }, { conv_key(80, 120, 68, 256, 256, 0, 0), 9 }, + { conv_key(80, 120, 68, 384, 192, 0, 0), 9 }, { conv_key(80, 120, 68, 512, 512, 0, 0), 14 }, + { conv_key(80, 120, 68, 768, 768, 0, 0), 14 }, { conv_key(80, 160, 90, 192, 192, 0, 0), 11 }, + { conv_key(80, 160, 90, 256, 128, 0, 0), 14 }, { conv_key(80, 160, 90, 256, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 384, 384, 0, 0), 14 }, { conv_key(80, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 512, 0, 0), 14 }, { conv_key(80, 240, 135, 256, 128, 0, 0), 14 }, + { conv_key(80, 240, 135, 384, 192, 0, 0), 14 }, { conv_key(80, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(80, 240, 135, 768, 768, 0, 0), 14 }, { conv_key(80, 240, 136, 128, 64, 0, 0), 2 }, + { conv_key(80, 240, 136, 128, 128, 0, 0), 2 }, { conv_key(80, 240, 136, 192, 192, 0, 0), 11 }, + { conv_key(80, 240, 136, 256, 128, 0, 0), 14 }, { conv_key(80, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 384, 384, 0, 0), 14 }, { conv_key(80, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 512, 0, 0), 14 }, { conv_key(80, 480, 270, 192, 192, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 128, 0, 0), 14 }, { conv_key(80, 480, 270, 256, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 384, 384, 0, 0), 14 }, { conv_key(80, 480, 270, 512, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 512, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 7, 4, 128, 64, 0, 0), 17 }, { conv_key(89, 7, 4, 128, 128, 0, 0), 29 }, + { conv_key(89, 13, 8, 128, 64, 0, 0), 29 }, { conv_key(89, 13, 8, 128, 128, 0, 0), 19 }, + { conv_key(89, 14, 8, 128, 64, 0, 0), 17 }, { conv_key(89, 14, 8, 128, 128, 0, 0), 19 }, + { conv_key(89, 14, 8, 256, 256, 0, 0), 8 }, { conv_key(89, 20, 12, 128, 64, 0, 0), 29 }, + { conv_key(89, 20, 12, 128, 128, 0, 0), 19 }, { conv_key(89, 26, 15, 256, 128, 0, 0), 19 }, + { conv_key(89, 26, 15, 384, 192, 0, 0), 18 }, { conv_key(89, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(89, 26, 15, 768, 768, 0, 0), 8 }, { conv_key(89, 26, 16, 128, 64, 0, 0), 19 }, + { conv_key(89, 26, 16, 128, 128, 0, 0), 8 }, { conv_key(89, 26, 16, 256, 256, 0, 0), 8 }, + { conv_key(89, 28, 16, 128, 64, 0, 0), 8 }, { conv_key(89, 28, 16, 128, 128, 0, 0), 19 }, + { conv_key(89, 28, 16, 256, 256, 0, 0), 19 }, { conv_key(89, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(89, 30, 17, 128, 64, 0, 0), 5 }, { conv_key(89, 30, 17, 128, 128, 0, 0), 7 }, + { conv_key(89, 40, 24, 128, 64, 0, 0), 29 }, { conv_key(89, 40, 24, 128, 128, 0, 0), 7 }, + { conv_key(89, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(89, 52, 30, 192, 192, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 128, 0, 0), 8 }, { conv_key(89, 52, 30, 256, 256, 0, 0), 8 }, + { conv_key(89, 52, 30, 384, 192, 0, 0), 29 }, { conv_key(89, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(89, 52, 30, 512, 256, 0, 0), 18 }, { conv_key(89, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(89, 52, 30, 768, 768, 0, 0), 14 }, { conv_key(89, 52, 32, 128, 64, 0, 0), 29 }, + { conv_key(89, 52, 32, 128, 128, 0, 0), 8 }, { conv_key(89, 52, 32, 256, 256, 0, 0), 8 }, + { conv_key(89, 52, 32, 512, 512, 0, 0), 18 }, { conv_key(89, 60, 34, 128, 64, 0, 0), 17 }, + { conv_key(89, 60, 34, 128, 128, 0, 0), 19 }, { conv_key(89, 60, 34, 256, 256, 0, 0), 18 }, + { conv_key(89, 80, 45, 256, 128, 0, 0), 7 }, { conv_key(89, 80, 45, 384, 192, 0, 0), 7 }, + { conv_key(89, 80, 45, 512, 512, 0, 0), 15 }, { conv_key(89, 80, 45, 768, 768, 0, 0), 14 }, + { conv_key(89, 80, 48, 128, 64, 0, 0), 8 }, { conv_key(89, 80, 48, 128, 128, 0, 0), 19 }, + { conv_key(89, 80, 48, 256, 256, 0, 0), 17 }, { conv_key(89, 80, 48, 512, 512, 0, 0), 15 }, + { conv_key(89, 104, 60, 192, 192, 0, 0), 7 }, { conv_key(89, 104, 60, 256, 128, 0, 0), 5 }, + { conv_key(89, 104, 60, 256, 256, 0, 0), 14 }, { conv_key(89, 104, 60, 384, 384, 0, 0), 14 }, + { conv_key(89, 104, 60, 512, 256, 0, 0), 14 }, { conv_key(89, 104, 60, 512, 512, 0, 0), 14 }, + { conv_key(89, 120, 68, 128, 64, 0, 0), 7 }, { conv_key(89, 120, 68, 128, 128, 0, 0), 7 }, + { conv_key(89, 120, 68, 256, 128, 0, 0), 5 }, { conv_key(89, 120, 68, 256, 256, 0, 0), 15 }, + { conv_key(89, 120, 68, 384, 192, 0, 0), 14 }, { conv_key(89, 120, 68, 512, 512, 0, 0), 9 }, + { conv_key(89, 120, 68, 768, 768, 0, 0), 14 }, { conv_key(89, 160, 90, 192, 192, 0, 0), 14 }, + { conv_key(89, 160, 90, 256, 128, 0, 0), 14 }, { conv_key(89, 160, 90, 256, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 384, 384, 0, 0), 14 }, { conv_key(89, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 512, 0, 0), 9 }, { conv_key(89, 240, 135, 256, 128, 0, 0), 14 }, + { conv_key(89, 240, 135, 384, 192, 0, 0), 14 }, { conv_key(89, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(89, 240, 135, 768, 768, 0, 0), 14 }, { conv_key(89, 240, 136, 128, 64, 0, 0), 5 }, + { conv_key(89, 240, 136, 128, 128, 0, 0), 9 }, { conv_key(89, 240, 136, 192, 192, 0, 0), 14 }, + { conv_key(89, 240, 136, 256, 128, 0, 0), 14 }, { conv_key(89, 240, 136, 256, 256, 0, 0), 9 }, + { conv_key(89, 240, 136, 384, 384, 0, 0), 9 }, { conv_key(89, 240, 136, 512, 256, 0, 0), 2 }, + { conv_key(89, 240, 136, 512, 512, 0, 0), 14 }, { conv_key(89, 480, 270, 192, 192, 0, 0), 5 }, + { conv_key(89, 480, 270, 256, 128, 0, 0), 7 }, { conv_key(89, 480, 270, 256, 256, 0, 0), 1 }, + { conv_key(89, 480, 270, 384, 384, 0, 0), 9 }, { conv_key(89, 480, 270, 512, 256, 0, 0), 10 }, + { conv_key(89, 480, 270, 512, 512, 0, 0), 10 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 7, 4, 128, 64, 0, 0), 8 }, { conv_key(90, 7, 4, 128, 128, 0, 0), 8 }, + { conv_key(90, 13, 8, 128, 64, 0, 0), 8 }, { conv_key(90, 13, 8, 128, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 128, 64, 0, 0), 8 }, { conv_key(90, 14, 8, 128, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 256, 256, 0, 0), 8 }, { conv_key(90, 20, 12, 128, 64, 0, 0), 8 }, + { conv_key(90, 20, 12, 128, 128, 0, 0), 8 }, { conv_key(90, 26, 15, 256, 128, 0, 0), 8 }, + { conv_key(90, 26, 15, 384, 192, 0, 0), 8 }, { conv_key(90, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(90, 26, 15, 768, 768, 0, 0), 8 }, { conv_key(90, 26, 16, 128, 64, 0, 0), 8 }, + { conv_key(90, 26, 16, 128, 128, 0, 0), 8 }, { conv_key(90, 26, 16, 256, 256, 0, 0), 8 }, + { conv_key(90, 28, 16, 128, 64, 0, 0), 8 }, { conv_key(90, 28, 16, 128, 128, 0, 0), 8 }, + { conv_key(90, 28, 16, 256, 256, 0, 0), 8 }, { conv_key(90, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(90, 30, 17, 128, 64, 0, 0), 8 }, { conv_key(90, 30, 17, 128, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 128, 64, 0, 0), 8 }, { conv_key(90, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(90, 52, 30, 192, 192, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 128, 0, 0), 8 }, { conv_key(90, 52, 30, 256, 256, 0, 0), 8 }, + { conv_key(90, 52, 30, 384, 192, 0, 0), 29 }, { conv_key(90, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 256, 0, 0), 29 }, { conv_key(90, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(90, 52, 30, 768, 768, 0, 0), 30 }, { conv_key(90, 52, 32, 128, 64, 0, 0), 8 }, + { conv_key(90, 52, 32, 128, 128, 0, 0), 8 }, { conv_key(90, 52, 32, 256, 256, 0, 0), 8 }, + { conv_key(90, 52, 32, 512, 512, 0, 0), 29 }, { conv_key(90, 60, 34, 128, 64, 0, 0), 8 }, + { conv_key(90, 60, 34, 128, 128, 0, 0), 8 }, { conv_key(90, 60, 34, 256, 256, 0, 0), 8 }, + { conv_key(90, 80, 45, 256, 128, 0, 0), 29 }, { conv_key(90, 80, 45, 384, 192, 0, 0), 31 }, + { conv_key(90, 80, 45, 512, 512, 0, 0), 30 }, { conv_key(90, 80, 45, 768, 768, 0, 0), 32 }, + { conv_key(90, 80, 48, 128, 64, 0, 0), 8 }, { conv_key(90, 80, 48, 128, 128, 0, 0), 8 }, + { conv_key(90, 80, 48, 256, 256, 0, 0), 29 }, { conv_key(90, 80, 48, 512, 512, 0, 0), 30 }, + { conv_key(90, 104, 60, 192, 192, 0, 0), 30 }, { conv_key(90, 104, 60, 256, 128, 0, 0), 30 }, + { conv_key(90, 104, 60, 256, 256, 0, 0), 30 }, { conv_key(90, 104, 60, 384, 384, 0, 0), 32 }, + { conv_key(90, 104, 60, 512, 256, 0, 0), 32 }, { conv_key(90, 104, 60, 512, 512, 0, 0), 32 }, + { conv_key(90, 120, 68, 128, 64, 0, 0), 29 }, { conv_key(90, 120, 68, 128, 128, 0, 0), 29 }, + { conv_key(90, 120, 68, 256, 128, 0, 0), 30 }, { conv_key(90, 120, 68, 256, 256, 0, 0), 30 }, + { conv_key(90, 120, 68, 384, 192, 0, 0), 29 }, { conv_key(90, 120, 68, 512, 512, 0, 0), 32 }, + { conv_key(90, 120, 68, 768, 768, 0, 0), 30 }, { conv_key(90, 160, 90, 192, 192, 0, 0), 28 }, + { conv_key(90, 160, 90, 256, 128, 0, 0), 34 }, { conv_key(90, 160, 90, 256, 256, 0, 0), 34 }, + { conv_key(90, 160, 90, 384, 384, 0, 0), 36 }, { conv_key(90, 160, 90, 512, 256, 0, 0), 36 }, + { conv_key(90, 160, 90, 512, 512, 0, 0), 32 }, { conv_key(90, 240, 135, 256, 128, 0, 0), 34 }, + { conv_key(90, 240, 135, 384, 192, 0, 0), 35 }, { conv_key(90, 240, 135, 512, 512, 0, 0), 37 }, + { conv_key(90, 240, 135, 768, 768, 0, 0), 37 }, { conv_key(90, 240, 136, 128, 64, 0, 0), 11 }, + { conv_key(90, 240, 136, 128, 128, 0, 0), 27 }, { conv_key(90, 240, 136, 192, 192, 0, 0), 34 }, + { conv_key(90, 240, 136, 256, 128, 0, 0), 34 }, { conv_key(90, 240, 136, 256, 256, 0, 0), 30 }, + { conv_key(90, 240, 136, 384, 384, 0, 0), 31 }, { conv_key(90, 240, 136, 512, 256, 0, 0), 32 }, + { conv_key(90, 240, 136, 512, 512, 0, 0), 32 }, { conv_key(90, 480, 270, 192, 192, 0, 0), 30 }, + { conv_key(90, 480, 270, 256, 128, 0, 0), 30 }, { conv_key(90, 480, 270, 256, 256, 0, 0), 30 }, + { conv_key(90, 480, 270, 384, 384, 0, 0), 35 }, { conv_key(90, 480, 270, 512, 256, 0, 0), 35 }, + { conv_key(90, 480, 270, 512, 512, 0, 0), 37 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 7, 4, 128, 64, 0, 0), 23 }, + { conv_key(100, 7, 4, 128, 128, 0, 0), 6 }, + { conv_key(100, 13, 8, 128, 64, 0, 0), 28 }, + { conv_key(100, 13, 8, 128, 128, 0, 0), 8 }, + { conv_key(100, 14, 8, 128, 64, 0, 0), 7 }, + { conv_key(100, 14, 8, 128, 128, 0, 0), 29 }, + { conv_key(100, 14, 8, 256, 256, 0, 0), 7 }, + { conv_key(100, 20, 12, 128, 64, 0, 0), 18 }, + { conv_key(100, 20, 12, 128, 128, 0, 0), 7 }, + { conv_key(100, 26, 15, 256, 128, 0, 0), 18 }, + { conv_key(100, 26, 15, 384, 192, 0, 0), 19 }, + { conv_key(100, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(100, 26, 15, 768, 768, 0, 0), 8 }, + { conv_key(100, 26, 16, 128, 64, 0, 0), 26 }, + { conv_key(100, 26, 16, 128, 128, 0, 0), 19 }, + { conv_key(100, 26, 16, 256, 256, 0, 0), 18 }, + { conv_key(100, 28, 16, 128, 64, 0, 0), 13 }, + { conv_key(100, 28, 16, 128, 128, 0, 0), 19 }, + { conv_key(100, 28, 16, 256, 256, 0, 0), 19 }, + { conv_key(100, 28, 16, 512, 512, 0, 0), 19 }, + { conv_key(100, 30, 17, 128, 64, 0, 0), 19 }, + { conv_key(100, 30, 17, 128, 128, 0, 0), 29 }, + { conv_key(100, 40, 24, 128, 64, 0, 0), 29 }, + { conv_key(100, 40, 24, 128, 128, 0, 0), 29 }, + { conv_key(100, 40, 24, 256, 256, 0, 0), 17 }, + { conv_key(100, 52, 30, 192, 192, 0, 0), 28 }, + { conv_key(100, 52, 30, 256, 128, 0, 0), 7 }, + { conv_key(100, 52, 30, 256, 256, 0, 0), 18 }, + { conv_key(100, 52, 30, 384, 192, 0, 0), 18 }, + { conv_key(100, 52, 30, 384, 384, 0, 0), 8 }, + { conv_key(100, 52, 30, 512, 256, 0, 0), 29 }, + { conv_key(100, 52, 30, 512, 512, 0, 0), 53 }, + { conv_key(100, 52, 30, 768, 768, 0, 0), 58 }, + { conv_key(100, 52, 32, 128, 64, 0, 0), 17 }, + { conv_key(100, 52, 32, 128, 128, 0, 0), 7 }, + { conv_key(100, 52, 32, 256, 256, 0, 0), 18 }, + { conv_key(100, 52, 32, 512, 512, 0, 0), 53 }, + { conv_key(100, 60, 34, 128, 64, 0, 0), 19 }, + { conv_key(100, 60, 34, 128, 128, 0, 0), 7 }, + { conv_key(100, 60, 34, 256, 256, 0, 0), 17 }, + { conv_key(100, 80, 45, 256, 128, 0, 0), 18 }, + { conv_key(100, 80, 45, 384, 192, 0, 0), 58 }, + { conv_key(100, 80, 45, 512, 512, 0, 0), 53 }, + { conv_key(100, 80, 45, 768, 768, 0, 0), 70 }, + { conv_key(100, 80, 48, 128, 64, 0, 0), 8 }, + { conv_key(100, 80, 48, 128, 128, 0, 0), 7 }, + { conv_key(100, 80, 48, 256, 256, 0, 0), 28 }, + { conv_key(100, 80, 48, 512, 512, 0, 0), 58 }, + { conv_key(100, 104, 60, 192, 192, 0, 0), 8 }, + { conv_key(100, 104, 60, 256, 128, 0, 0), 29 }, + { conv_key(100, 104, 60, 256, 256, 0, 0), 29 }, + { conv_key(100, 104, 60, 384, 384, 0, 0), 82 }, + { conv_key(100, 104, 60, 512, 256, 0, 0), 87 }, + { conv_key(100, 104, 60, 512, 512, 0, 0), 68 }, + { conv_key(100, 120, 68, 128, 64, 0, 0), 18 }, + { conv_key(100, 120, 68, 128, 128, 0, 0), 26 }, + { conv_key(100, 120, 68, 256, 128, 0, 0), 29 }, + { conv_key(100, 120, 68, 256, 256, 0, 0), 29 }, + { conv_key(100, 120, 68, 384, 192, 0, 0), 58 }, + { conv_key(100, 120, 68, 512, 512, 0, 0), 92 }, + { conv_key(100, 120, 68, 768, 768, 0, 0), 69 }, + { conv_key(100, 160, 90, 192, 192, 0, 0), 87 }, + { conv_key(100, 160, 90, 256, 128, 0, 0), 63 }, + { conv_key(100, 160, 90, 256, 256, 0, 0), 92 }, + { conv_key(100, 160, 90, 384, 384, 0, 0), 68 }, + { conv_key(100, 160, 90, 512, 256, 0, 0), 75 }, + { conv_key(100, 160, 90, 512, 512, 0, 0), 76 }, + { conv_key(100, 240, 135, 256, 128, 0, 0), 75 }, + { conv_key(100, 240, 135, 384, 192, 0, 0), 75 }, + { conv_key(100, 240, 135, 512, 512, 0, 0), 76 }, + { conv_key(100, 240, 135, 768, 768, 0, 0), 77 }, + { conv_key(100, 240, 136, 128, 64, 0, 0), 58 }, + { conv_key(100, 240, 136, 128, 128, 0, 0), 82 }, + { conv_key(100, 240, 136, 192, 192, 0, 0), 75 }, + { conv_key(100, 240, 136, 256, 128, 0, 0), 75 }, + { conv_key(100, 240, 136, 256, 256, 0, 0), 75 }, + { conv_key(100, 240, 136, 384, 384, 0, 0), 68 }, + { conv_key(100, 240, 136, 512, 256, 0, 0), 76 }, + { conv_key(100, 240, 136, 512, 512, 0, 0), 76 }, + { conv_key(100, 480, 270, 192, 192, 0, 0), 75 }, + { conv_key(100, 480, 270, 256, 128, 0, 0), 92 }, + { conv_key(100, 480, 270, 256, 256, 0, 0), 75 }, + { conv_key(100, 480, 270, 384, 384, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 256, 0, 0), 75 }, + { conv_key(100, 480, 270, 512, 512, 0, 0), 75 }, +#endif +}; + +at::Tensor conv1x1_bias_shortcut(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const at::Tensor& shortcut, at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + return out + bias.reshape({ 1, -1, 1, 1 }) + shortcut; + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass(out_buf, feature, weight, bias, shortcut); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS_SHORTCUT, + HINT_MAP_BIAS_SHORTCUT_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut2.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut2.cu new file mode 100644 index 0000000..3f12b41 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut2.cu @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_SHORTCUT2_NAME = "HINT_MAP_BIAS_SHORTCUT2"; +std::unordered_map HINT_MAP_BIAS_SHORTCUT2 = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 7, 4, 128, 128, 0, 0), 19 }, { conv_key(80, 13, 8, 128, 128, 0, 0), 8 }, + { conv_key(80, 14, 8, 128, 128, 0, 0), 8 }, { conv_key(80, 20, 12, 128, 128, 0, 0), 7 }, + { conv_key(80, 26, 16, 128, 128, 0, 0), 7 }, { conv_key(80, 28, 16, 128, 128, 0, 0), 29 }, + { conv_key(80, 30, 17, 128, 128, 0, 0), 8 }, { conv_key(80, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(80, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(80, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(80, 52, 32, 128, 128, 0, 0), 19 }, { conv_key(80, 60, 34, 128, 128, 0, 0), 8 }, + { conv_key(80, 60, 34, 256, 256, 0, 0), 29 }, { conv_key(80, 80, 45, 512, 512, 0, 0), 29 }, + { conv_key(80, 80, 48, 128, 128, 0, 0), 29 }, { conv_key(80, 80, 48, 256, 256, 0, 0), 14 }, + { conv_key(80, 104, 60, 384, 384, 0, 0), 14 }, { conv_key(80, 120, 68, 128, 128, 0, 0), 7 }, + { conv_key(80, 120, 68, 256, 256, 0, 0), 14 }, { conv_key(80, 120, 68, 512, 512, 0, 0), 14 }, + { conv_key(80, 160, 90, 384, 384, 0, 0), 14 }, { conv_key(80, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(80, 240, 136, 128, 128, 0, 0), 2 }, { conv_key(80, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 384, 384, 0, 0), 14 }, { conv_key(80, 480, 270, 384, 384, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 7, 4, 128, 128, 0, 0), 19 }, { conv_key(89, 13, 8, 128, 128, 0, 0), 8 }, + { conv_key(89, 14, 8, 128, 128, 0, 0), 7 }, { conv_key(89, 20, 12, 128, 128, 0, 0), 7 }, + { conv_key(89, 26, 16, 128, 128, 0, 0), 19 }, { conv_key(89, 28, 16, 128, 128, 0, 0), 19 }, + { conv_key(89, 30, 17, 128, 128, 0, 0), 7 }, { conv_key(89, 40, 24, 128, 128, 0, 0), 19 }, + { conv_key(89, 40, 24, 256, 256, 0, 0), 19 }, { conv_key(89, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(89, 52, 32, 128, 128, 0, 0), 19 }, { conv_key(89, 60, 34, 128, 128, 0, 0), 8 }, + { conv_key(89, 60, 34, 256, 256, 0, 0), 8 }, { conv_key(89, 80, 45, 512, 512, 0, 0), 16 }, + { conv_key(89, 80, 48, 128, 128, 0, 0), 19 }, { conv_key(89, 80, 48, 256, 256, 0, 0), 7 }, + { conv_key(89, 104, 60, 384, 384, 0, 0), 14 }, { conv_key(89, 120, 68, 128, 128, 0, 0), 7 }, + { conv_key(89, 120, 68, 256, 256, 0, 0), 14 }, { conv_key(89, 120, 68, 512, 512, 0, 0), 14 }, + { conv_key(89, 160, 90, 384, 384, 0, 0), 14 }, { conv_key(89, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(89, 240, 136, 128, 128, 0, 0), 2 }, { conv_key(89, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(89, 240, 136, 384, 384, 0, 0), 14 }, { conv_key(89, 480, 270, 384, 384, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 7, 4, 128, 128, 0, 0), 8 }, { conv_key(90, 13, 8, 128, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 128, 128, 0, 0), 8 }, { conv_key(90, 20, 12, 128, 128, 0, 0), 8 }, + { conv_key(90, 26, 16, 128, 128, 0, 0), 8 }, { conv_key(90, 28, 16, 128, 128, 0, 0), 8 }, + { conv_key(90, 30, 17, 128, 128, 0, 0), 8 }, { conv_key(90, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(90, 52, 30, 384, 384, 0, 0), 29 }, + { conv_key(90, 52, 32, 128, 128, 0, 0), 8 }, { conv_key(90, 60, 34, 128, 128, 0, 0), 8 }, + { conv_key(90, 60, 34, 256, 256, 0, 0), 8 }, { conv_key(90, 80, 45, 512, 512, 0, 0), 30 }, + { conv_key(90, 80, 48, 128, 128, 0, 0), 8 }, { conv_key(90, 80, 48, 256, 256, 0, 0), 29 }, + { conv_key(90, 104, 60, 384, 384, 0, 0), 34 }, { conv_key(90, 120, 68, 128, 128, 0, 0), 29 }, + { conv_key(90, 120, 68, 256, 256, 0, 0), 30 }, { conv_key(90, 120, 68, 512, 512, 0, 0), 32 }, + { conv_key(90, 160, 90, 384, 384, 0, 0), 31 }, { conv_key(90, 240, 135, 512, 512, 0, 0), 40 }, + { conv_key(90, 240, 136, 128, 128, 0, 0), 11 }, { conv_key(90, 240, 136, 256, 256, 0, 0), 30 }, + { conv_key(90, 240, 136, 384, 384, 0, 0), 31 }, { conv_key(90, 480, 270, 384, 384, 0, 0), 35 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 7, 4, 128, 128, 0, 0), 25 }, + { conv_key(100, 13, 8, 128, 128, 0, 0), 25 }, + { conv_key(100, 14, 8, 128, 128, 0, 0), 6 }, + { conv_key(100, 20, 12, 128, 128, 0, 0), 7 }, + { conv_key(100, 26, 16, 128, 128, 0, 0), 17 }, + { conv_key(100, 28, 16, 128, 128, 0, 0), 17 }, + { conv_key(100, 30, 17, 128, 128, 0, 0), 6 }, + { conv_key(100, 40, 24, 128, 128, 0, 0), 17 }, + { conv_key(100, 40, 24, 256, 256, 0, 0), 58 }, + { conv_key(100, 52, 30, 384, 384, 0, 0), 8 }, + { conv_key(100, 52, 32, 128, 128, 0, 0), 7 }, + { conv_key(100, 60, 34, 128, 128, 0, 0), 7 }, + { conv_key(100, 60, 34, 256, 256, 0, 0), 53 }, + { conv_key(100, 80, 45, 512, 512, 0, 0), 88 }, + { conv_key(100, 80, 48, 128, 128, 0, 0), 19 }, + { conv_key(100, 80, 48, 256, 256, 0, 0), 63 }, + { conv_key(100, 104, 60, 384, 384, 0, 0), 87 }, + { conv_key(100, 120, 68, 128, 128, 0, 0), 8 }, + { conv_key(100, 120, 68, 256, 256, 0, 0), 83 }, + { conv_key(100, 120, 68, 512, 512, 0, 0), 47 }, + { conv_key(100, 160, 90, 384, 384, 0, 0), 68 }, + { conv_key(100, 240, 135, 512, 512, 0, 0), 46 }, + { conv_key(100, 240, 136, 128, 128, 0, 0), 87 }, + { conv_key(100, 240, 136, 256, 256, 0, 0), 77 }, + { conv_key(100, 240, 136, 384, 384, 0, 0), 68 }, + { conv_key(100, 480, 270, 384, 384, 0, 0), 68 }, +#endif +}; + +at::Tensor conv1x1_bias_shortcut2(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const at::Tensor& shortcut1, + const at::Tensor& shortcut2, at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + return out + bias.reshape({ 1, -1, 1, 1 }) + shortcut1 + shortcut2; + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass(out_buf, feature, weight, bias, + shortcut1, shortcut2); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS_SHORTCUT2, + HINT_MAP_BIAS_SHORTCUT2_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut_with_quant.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut_with_quant.cu new file mode 100644 index 0000000..38d1abf --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_shortcut_with_quant.cu @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_SHORTCUT_WITH_QUANT_NAME = "HINT_MAP_BIAS_SHORTCUT_WITH_QUANT"; +std::unordered_map HINT_MAP_BIAS_SHORTCUT_WITH_QUANT = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 52, 30, 256, 128, 0, 0), 8 }, { conv_key(80, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(80, 104, 60, 256, 128, 0, 0), 14 }, { conv_key(80, 104, 60, 512, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 256, 128, 0, 0), 14 }, { conv_key(80, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 512, 0, 0), 14 }, { conv_key(80, 240, 136, 256, 128, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 256, 0, 0), 14 }, { conv_key(80, 240, 136, 512, 512, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 128, 0, 0), 14 }, { conv_key(80, 480, 270, 512, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 512, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 52, 30, 256, 128, 0, 0), 19 }, { conv_key(89, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(89, 104, 60, 256, 128, 0, 0), 5 }, { conv_key(89, 104, 60, 512, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 256, 128, 0, 0), 14 }, { conv_key(89, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 512, 0, 0), 14 }, { conv_key(89, 240, 136, 256, 128, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 256, 0, 0), 2 }, { conv_key(89, 240, 136, 512, 512, 0, 0), 2 }, + { conv_key(89, 480, 270, 256, 128, 0, 0), 7 }, { conv_key(89, 480, 270, 512, 256, 0, 0), 10 }, + { conv_key(89, 480, 270, 512, 512, 0, 0), 9 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 52, 30, 256, 128, 0, 0), 8 }, { conv_key(90, 52, 30, 512, 256, 0, 0), 29 }, + { conv_key(90, 104, 60, 256, 128, 0, 0), 30 }, { conv_key(90, 104, 60, 512, 256, 0, 0), 32 }, + { conv_key(90, 160, 90, 256, 128, 0, 0), 34 }, { conv_key(90, 160, 90, 512, 256, 0, 0), 36 }, + { conv_key(90, 160, 90, 512, 512, 0, 0), 36 }, { conv_key(90, 240, 136, 256, 128, 0, 0), 33 }, + { conv_key(90, 240, 136, 512, 256, 0, 0), 30 }, { conv_key(90, 240, 136, 512, 512, 0, 0), 46 }, + { conv_key(90, 480, 270, 256, 128, 0, 0), 30 }, { conv_key(90, 480, 270, 512, 256, 0, 0), 37 }, + { conv_key(90, 480, 270, 512, 512, 0, 0), 46 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 52, 30, 256, 128, 0, 0), 8 }, + { conv_key(100, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(100, 104, 60, 256, 128, 0, 0), 29 }, + { conv_key(100, 104, 60, 512, 256, 0, 0), 82 }, + { conv_key(100, 160, 90, 256, 128, 0, 0), 63 }, + { conv_key(100, 160, 90, 512, 256, 0, 0), 75 }, + { conv_key(100, 160, 90, 512, 512, 0, 0), 75 }, + { conv_key(100, 240, 136, 256, 128, 0, 0), 63 }, + { conv_key(100, 240, 136, 512, 256, 0, 0), 75 }, + { conv_key(100, 240, 136, 512, 512, 0, 0), 76 }, + { conv_key(100, 480, 270, 256, 128, 0, 0), 92 }, + { conv_key(100, 480, 270, 512, 256, 0, 0), 92 }, + { conv_key(100, 480, 270, 512, 512, 0, 0), 75 }, +#endif +}; + +at::Tensor conv1x1_bias_shortcut_with_quant(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& bias, + const at::Tensor& shortcut, const at::Tensor& quant, + at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + return (out + bias.reshape({ 1, -1, 1, 1 }) + shortcut) * quant; + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass(out_buf, feature, weight, bias, + shortcut, at::nullopt, quant); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS_SHORTCUT_WITH_QUANT, + HINT_MAP_BIAS_SHORTCUT_WITH_QUANT_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_with_quant.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias_with_quant.cu new file mode 100644 index 0000000..614a507 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_with_quant.cu @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_WITH_QUANT_NAME = "HINT_MAP_BIAS_WITH_QUANT"; +std::unordered_map HINT_MAP_BIAS_WITH_QUANT = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 52, 30, 256, 256, 0, 0), 19 }, { conv_key(80, 104, 60, 256, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 256, 256, 0, 0), 14 }, { conv_key(80, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 256, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 52, 30, 256, 256, 0, 0), 8 }, { conv_key(89, 104, 60, 256, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 256, 256, 0, 0), 14 }, { conv_key(89, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(89, 480, 270, 256, 256, 0, 0), 1 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 52, 30, 256, 256, 0, 0), 8 }, { conv_key(90, 104, 60, 256, 256, 0, 0), 30 }, + { conv_key(90, 160, 90, 256, 256, 0, 0), 34 }, { conv_key(90, 240, 136, 256, 256, 0, 0), 37 }, + { conv_key(90, 480, 270, 256, 256, 0, 0), 37 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 52, 30, 256, 256, 0, 0), 19 }, + { conv_key(100, 104, 60, 256, 256, 0, 0), 63 }, + { conv_key(100, 160, 90, 256, 256, 0, 0), 92 }, + { conv_key(100, 240, 136, 256, 256, 0, 0), 63 }, + { conv_key(100, 480, 270, 256, 256, 0, 0), 75 }, +#endif +}; + +at::Tensor conv1x1_bias_with_quant(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const at::Tensor& quant, at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + return (out + bias.reshape({ 1, -1, 1, 1 })) * quant; + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass(out_buf, feature, weight, bias, + at::nullopt, at::nullopt, quant); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS_WITH_QUANT, + HINT_MAP_BIAS_WITH_QUANT_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu.cu new file mode 100644 index 0000000..e25c7b5 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu.cu @@ -0,0 +1,248 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_WSILU_NAME = "HINT_MAP_BIAS_WSILU"; +std::unordered_map HINT_MAP_BIAS_WSILU = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 7, 4, 64, 128, 0, 0), 8 }, { conv_key(80, 7, 4, 128, 128, 0, 0), 7 }, + { conv_key(80, 13, 8, 64, 128, 0, 0), 8 }, { conv_key(80, 13, 8, 128, 128, 0, 0), 19 }, + { conv_key(80, 14, 8, 64, 128, 0, 0), 7 }, { conv_key(80, 14, 8, 128, 128, 0, 0), 19 }, + { conv_key(80, 14, 8, 256, 256, 0, 0), 8 }, { conv_key(80, 20, 12, 64, 128, 0, 0), 19 }, + { conv_key(80, 20, 12, 128, 128, 0, 0), 8 }, { conv_key(80, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(80, 26, 15, 192, 384, 0, 0), 8 }, { conv_key(80, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(80, 26, 15, 768, 768, 0, 0), 8 }, { conv_key(80, 26, 16, 64, 128, 0, 0), 8 }, + { conv_key(80, 26, 16, 128, 128, 0, 0), 7 }, { conv_key(80, 26, 16, 256, 256, 0, 0), 19 }, + { conv_key(80, 28, 16, 64, 128, 0, 0), 19 }, { conv_key(80, 28, 16, 128, 128, 0, 0), 19 }, + { conv_key(80, 28, 16, 256, 256, 0, 0), 8 }, { conv_key(80, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(80, 30, 17, 64, 128, 0, 0), 8 }, { conv_key(80, 30, 17, 128, 128, 0, 0), 8 }, + { conv_key(80, 40, 24, 64, 128, 0, 0), 8 }, { conv_key(80, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(80, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(80, 52, 30, 128, 256, 0, 0), 8 }, + { conv_key(80, 52, 30, 192, 192, 0, 0), 8 }, { conv_key(80, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(80, 52, 30, 256, 256, 0, 0), 19 }, { conv_key(80, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(80, 52, 30, 384, 384, 0, 0), 29 }, { conv_key(80, 52, 30, 512, 512, 0, 0), 18 }, + { conv_key(80, 52, 30, 768, 768, 0, 0), 14 }, { conv_key(80, 52, 32, 64, 128, 0, 0), 19 }, + { conv_key(80, 52, 32, 128, 128, 0, 0), 8 }, { conv_key(80, 52, 32, 256, 256, 0, 0), 19 }, + { conv_key(80, 52, 32, 512, 512, 0, 0), 29 }, { conv_key(80, 60, 34, 64, 128, 0, 0), 19 }, + { conv_key(80, 60, 34, 128, 128, 0, 0), 8 }, { conv_key(80, 60, 34, 256, 256, 0, 0), 29 }, + { conv_key(80, 80, 45, 128, 256, 0, 0), 29 }, { conv_key(80, 80, 45, 192, 384, 0, 0), 8 }, + { conv_key(80, 80, 45, 512, 512, 0, 0), 29 }, { conv_key(80, 80, 45, 768, 768, 0, 0), 9 }, + { conv_key(80, 80, 48, 64, 128, 0, 0), 8 }, { conv_key(80, 80, 48, 128, 128, 0, 0), 7 }, + { conv_key(80, 80, 48, 256, 256, 0, 0), 29 }, { conv_key(80, 80, 48, 512, 512, 0, 0), 29 }, + { conv_key(80, 104, 60, 128, 256, 0, 0), 29 }, { conv_key(80, 104, 60, 192, 192, 0, 0), 29 }, + { conv_key(80, 104, 60, 256, 256, 0, 0), 14 }, { conv_key(80, 104, 60, 256, 512, 0, 0), 14 }, + { conv_key(80, 104, 60, 384, 384, 0, 0), 14 }, { conv_key(80, 104, 60, 512, 512, 0, 0), 14 }, + { conv_key(80, 120, 68, 64, 128, 0, 0), 8 }, { conv_key(80, 120, 68, 128, 128, 0, 0), 7 }, + { conv_key(80, 120, 68, 128, 256, 0, 0), 14 }, { conv_key(80, 120, 68, 192, 384, 0, 0), 25 }, + { conv_key(80, 120, 68, 256, 256, 0, 0), 14 }, { conv_key(80, 120, 68, 512, 512, 0, 0), 14 }, + { conv_key(80, 120, 68, 768, 768, 0, 0), 14 }, { conv_key(80, 160, 90, 128, 256, 0, 0), 5 }, + { conv_key(80, 160, 90, 192, 192, 0, 0), 11 }, { conv_key(80, 160, 90, 256, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 256, 512, 0, 0), 14 }, { conv_key(80, 160, 90, 384, 384, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 512, 0, 0), 14 }, { conv_key(80, 240, 135, 128, 256, 0, 0), 15 }, + { conv_key(80, 240, 135, 192, 384, 0, 0), 11 }, { conv_key(80, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(80, 240, 135, 768, 768, 0, 0), 14 }, { conv_key(80, 240, 136, 64, 128, 0, 0), 7 }, + { conv_key(80, 240, 136, 128, 128, 0, 0), 2 }, { conv_key(80, 240, 136, 128, 256, 0, 0), 2 }, + { conv_key(80, 240, 136, 192, 192, 0, 0), 11 }, { conv_key(80, 240, 136, 256, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 256, 512, 0, 0), 14 }, { conv_key(80, 240, 136, 384, 384, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 512, 0, 0), 14 }, { conv_key(80, 480, 270, 128, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 192, 192, 0, 0), 14 }, { conv_key(80, 480, 270, 256, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 256, 512, 0, 0), 14 }, { conv_key(80, 480, 270, 384, 384, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 512, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 7, 4, 64, 128, 0, 0), 19 }, { conv_key(89, 7, 4, 128, 128, 0, 0), 19 }, + { conv_key(89, 13, 8, 64, 128, 0, 0), 7 }, { conv_key(89, 13, 8, 128, 128, 0, 0), 19 }, + { conv_key(89, 14, 8, 64, 128, 0, 0), 7 }, { conv_key(89, 14, 8, 128, 128, 0, 0), 19 }, + { conv_key(89, 14, 8, 256, 256, 0, 0), 8 }, { conv_key(89, 20, 12, 64, 128, 0, 0), 8 }, + { conv_key(89, 20, 12, 128, 128, 0, 0), 8 }, { conv_key(89, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(89, 26, 15, 192, 384, 0, 0), 19 }, { conv_key(89, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(89, 26, 15, 768, 768, 0, 0), 8 }, { conv_key(89, 26, 16, 64, 128, 0, 0), 8 }, + { conv_key(89, 26, 16, 128, 128, 0, 0), 7 }, { conv_key(89, 26, 16, 256, 256, 0, 0), 19 }, + { conv_key(89, 28, 16, 64, 128, 0, 0), 8 }, { conv_key(89, 28, 16, 128, 128, 0, 0), 7 }, + { conv_key(89, 28, 16, 256, 256, 0, 0), 19 }, { conv_key(89, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(89, 30, 17, 64, 128, 0, 0), 19 }, { conv_key(89, 30, 17, 128, 128, 0, 0), 19 }, + { conv_key(89, 40, 24, 64, 128, 0, 0), 8 }, { conv_key(89, 40, 24, 128, 128, 0, 0), 19 }, + { conv_key(89, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(89, 52, 30, 128, 256, 0, 0), 8 }, + { conv_key(89, 52, 30, 192, 192, 0, 0), 8 }, { conv_key(89, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(89, 52, 30, 256, 256, 0, 0), 8 }, { conv_key(89, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(89, 52, 30, 384, 384, 0, 0), 29 }, { conv_key(89, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(89, 52, 30, 768, 768, 0, 0), 14 }, { conv_key(89, 52, 32, 64, 128, 0, 0), 19 }, + { conv_key(89, 52, 32, 128, 128, 0, 0), 7 }, { conv_key(89, 52, 32, 256, 256, 0, 0), 8 }, + { conv_key(89, 52, 32, 512, 512, 0, 0), 29 }, { conv_key(89, 60, 34, 64, 128, 0, 0), 19 }, + { conv_key(89, 60, 34, 128, 128, 0, 0), 19 }, { conv_key(89, 60, 34, 256, 256, 0, 0), 29 }, + { conv_key(89, 80, 45, 128, 256, 0, 0), 8 }, { conv_key(89, 80, 45, 192, 384, 0, 0), 17 }, + { conv_key(89, 80, 45, 512, 512, 0, 0), 14 }, { conv_key(89, 80, 45, 768, 768, 0, 0), 14 }, + { conv_key(89, 80, 48, 64, 128, 0, 0), 19 }, { conv_key(89, 80, 48, 128, 128, 0, 0), 19 }, + { conv_key(89, 80, 48, 256, 256, 0, 0), 7 }, { conv_key(89, 80, 48, 512, 512, 0, 0), 14 }, + { conv_key(89, 104, 60, 128, 256, 0, 0), 17 }, { conv_key(89, 104, 60, 192, 192, 0, 0), 7 }, + { conv_key(89, 104, 60, 256, 256, 0, 0), 14 }, { conv_key(89, 104, 60, 256, 512, 0, 0), 14 }, + { conv_key(89, 104, 60, 384, 384, 0, 0), 5 }, { conv_key(89, 104, 60, 512, 512, 0, 0), 10 }, + { conv_key(89, 120, 68, 64, 128, 0, 0), 19 }, { conv_key(89, 120, 68, 128, 128, 0, 0), 7 }, + { conv_key(89, 120, 68, 128, 256, 0, 0), 7 }, { conv_key(89, 120, 68, 192, 384, 0, 0), 14 }, + { conv_key(89, 120, 68, 256, 256, 0, 0), 5 }, { conv_key(89, 120, 68, 512, 512, 0, 0), 9 }, + { conv_key(89, 120, 68, 768, 768, 0, 0), 14 }, { conv_key(89, 160, 90, 128, 256, 0, 0), 11 }, + { conv_key(89, 160, 90, 192, 192, 0, 0), 6 }, { conv_key(89, 160, 90, 256, 256, 0, 0), 9 }, + { conv_key(89, 160, 90, 256, 512, 0, 0), 9 }, { conv_key(89, 160, 90, 384, 384, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 512, 0, 0), 9 }, { conv_key(89, 240, 135, 128, 256, 0, 0), 14 }, + { conv_key(89, 240, 135, 192, 384, 0, 0), 14 }, { conv_key(89, 240, 135, 512, 512, 0, 0), 14 }, + { conv_key(89, 240, 135, 768, 768, 0, 0), 14 }, { conv_key(89, 240, 136, 64, 128, 0, 0), 7 }, + { conv_key(89, 240, 136, 128, 128, 0, 0), 9 }, { conv_key(89, 240, 136, 128, 256, 0, 0), 9 }, + { conv_key(89, 240, 136, 192, 192, 0, 0), 14 }, { conv_key(89, 240, 136, 256, 256, 0, 0), 9 }, + { conv_key(89, 240, 136, 256, 512, 0, 0), 9 }, { conv_key(89, 240, 136, 384, 384, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 512, 0, 0), 14 }, { conv_key(89, 480, 270, 128, 256, 0, 0), 5 }, + { conv_key(89, 480, 270, 192, 192, 0, 0), 7 }, { conv_key(89, 480, 270, 256, 256, 0, 0), 14 }, + { conv_key(89, 480, 270, 256, 512, 0, 0), 14 }, { conv_key(89, 480, 270, 384, 384, 0, 0), 14 }, + { conv_key(89, 480, 270, 512, 512, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 7, 4, 64, 128, 0, 0), 8 }, { conv_key(90, 7, 4, 128, 128, 0, 0), 8 }, + { conv_key(90, 13, 8, 64, 128, 0, 0), 8 }, { conv_key(90, 13, 8, 128, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 64, 128, 0, 0), 8 }, { conv_key(90, 14, 8, 128, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 256, 256, 0, 0), 8 }, { conv_key(90, 20, 12, 64, 128, 0, 0), 8 }, + { conv_key(90, 20, 12, 128, 128, 0, 0), 8 }, { conv_key(90, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(90, 26, 15, 192, 384, 0, 0), 8 }, { conv_key(90, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(90, 26, 15, 768, 768, 0, 0), 8 }, { conv_key(90, 26, 16, 64, 128, 0, 0), 8 }, + { conv_key(90, 26, 16, 128, 128, 0, 0), 8 }, { conv_key(90, 26, 16, 256, 256, 0, 0), 8 }, + { conv_key(90, 28, 16, 64, 128, 0, 0), 8 }, { conv_key(90, 28, 16, 128, 128, 0, 0), 8 }, + { conv_key(90, 28, 16, 256, 256, 0, 0), 8 }, { conv_key(90, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(90, 30, 17, 64, 128, 0, 0), 8 }, { conv_key(90, 30, 17, 128, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 64, 128, 0, 0), 8 }, { conv_key(90, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 256, 256, 0, 0), 8 }, { conv_key(90, 52, 30, 128, 256, 0, 0), 8 }, + { conv_key(90, 52, 30, 192, 192, 0, 0), 8 }, { conv_key(90, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(90, 52, 30, 256, 256, 0, 0), 8 }, { conv_key(90, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(90, 52, 30, 384, 384, 0, 0), 29 }, { conv_key(90, 52, 30, 512, 512, 0, 0), 29 }, + { conv_key(90, 52, 30, 768, 768, 0, 0), 30 }, { conv_key(90, 52, 32, 64, 128, 0, 0), 8 }, + { conv_key(90, 52, 32, 128, 128, 0, 0), 8 }, { conv_key(90, 52, 32, 256, 256, 0, 0), 8 }, + { conv_key(90, 52, 32, 512, 512, 0, 0), 29 }, { conv_key(90, 60, 34, 64, 128, 0, 0), 8 }, + { conv_key(90, 60, 34, 128, 128, 0, 0), 8 }, { conv_key(90, 60, 34, 256, 256, 0, 0), 8 }, + { conv_key(90, 80, 45, 128, 256, 0, 0), 8 }, { conv_key(90, 80, 45, 192, 384, 0, 0), 29 }, + { conv_key(90, 80, 45, 512, 512, 0, 0), 30 }, { conv_key(90, 80, 45, 768, 768, 0, 0), 33 }, + { conv_key(90, 80, 48, 64, 128, 0, 0), 8 }, { conv_key(90, 80, 48, 128, 128, 0, 0), 8 }, + { conv_key(90, 80, 48, 256, 256, 0, 0), 29 }, { conv_key(90, 80, 48, 512, 512, 0, 0), 30 }, + { conv_key(90, 104, 60, 128, 256, 0, 0), 29 }, { conv_key(90, 104, 60, 192, 192, 0, 0), 30 }, + { conv_key(90, 104, 60, 256, 256, 0, 0), 30 }, { conv_key(90, 104, 60, 256, 512, 0, 0), 30 }, + { conv_key(90, 104, 60, 384, 384, 0, 0), 29 }, { conv_key(90, 104, 60, 512, 512, 0, 0), 32 }, + { conv_key(90, 120, 68, 64, 128, 0, 0), 8 }, { conv_key(90, 120, 68, 128, 128, 0, 0), 29 }, + { conv_key(90, 120, 68, 128, 256, 0, 0), 29 }, { conv_key(90, 120, 68, 192, 384, 0, 0), 30 }, + { conv_key(90, 120, 68, 256, 256, 0, 0), 30 }, { conv_key(90, 120, 68, 512, 512, 0, 0), 32 }, + { conv_key(90, 120, 68, 768, 768, 0, 0), 30 }, { conv_key(90, 160, 90, 128, 256, 0, 0), 29 }, + { conv_key(90, 160, 90, 192, 192, 0, 0), 28 }, { conv_key(90, 160, 90, 256, 256, 0, 0), 34 }, + { conv_key(90, 160, 90, 256, 512, 0, 0), 34 }, { conv_key(90, 160, 90, 384, 384, 0, 0), 14 }, + { conv_key(90, 160, 90, 512, 512, 0, 0), 36 }, { conv_key(90, 240, 135, 128, 256, 0, 0), 27 }, + { conv_key(90, 240, 135, 192, 384, 0, 0), 11 }, { conv_key(90, 240, 135, 512, 512, 0, 0), 36 }, + { conv_key(90, 240, 135, 768, 768, 0, 0), 37 }, { conv_key(90, 240, 136, 64, 128, 0, 0), 28 }, + { conv_key(90, 240, 136, 128, 128, 0, 0), 27 }, { conv_key(90, 240, 136, 128, 256, 0, 0), 14 }, + { conv_key(90, 240, 136, 192, 192, 0, 0), 11 }, { conv_key(90, 240, 136, 256, 256, 0, 0), 34 }, + { conv_key(90, 240, 136, 256, 512, 0, 0), 33 }, { conv_key(90, 240, 136, 384, 384, 0, 0), 35 }, + { conv_key(90, 240, 136, 512, 512, 0, 0), 36 }, { conv_key(90, 480, 270, 128, 256, 0, 0), 35 }, + { conv_key(90, 480, 270, 192, 192, 0, 0), 37 }, { conv_key(90, 480, 270, 256, 256, 0, 0), 37 }, + { conv_key(90, 480, 270, 256, 512, 0, 0), 37 }, { conv_key(90, 480, 270, 384, 384, 0, 0), 35 }, + { conv_key(90, 480, 270, 512, 512, 0, 0), 36 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 7, 4, 64, 128, 0, 0), 19 }, + { conv_key(100, 7, 4, 128, 128, 0, 0), 18 }, + { conv_key(100, 13, 8, 64, 128, 0, 0), 8 }, + { conv_key(100, 13, 8, 128, 128, 0, 0), 6 }, + { conv_key(100, 14, 8, 64, 128, 0, 0), 7 }, + { conv_key(100, 14, 8, 128, 128, 0, 0), 8 }, + { conv_key(100, 14, 8, 256, 256, 0, 0), 7 }, + { conv_key(100, 20, 12, 64, 128, 0, 0), 7 }, + { conv_key(100, 20, 12, 128, 128, 0, 0), 7 }, + { conv_key(100, 26, 15, 128, 256, 0, 0), 8 }, + { conv_key(100, 26, 15, 192, 384, 0, 0), 8 }, + { conv_key(100, 26, 15, 512, 512, 0, 0), 8 }, + { conv_key(100, 26, 15, 768, 768, 0, 0), 8 }, + { conv_key(100, 26, 16, 64, 128, 0, 0), 19 }, + { conv_key(100, 26, 16, 128, 128, 0, 0), 7 }, + { conv_key(100, 26, 16, 256, 256, 0, 0), 29 }, + { conv_key(100, 28, 16, 64, 128, 0, 0), 19 }, + { conv_key(100, 28, 16, 128, 128, 0, 0), 6 }, + { conv_key(100, 28, 16, 256, 256, 0, 0), 8 }, + { conv_key(100, 28, 16, 512, 512, 0, 0), 8 }, + { conv_key(100, 30, 17, 64, 128, 0, 0), 18 }, + { conv_key(100, 30, 17, 128, 128, 0, 0), 19 }, + { conv_key(100, 40, 24, 64, 128, 0, 0), 19 }, + { conv_key(100, 40, 24, 128, 128, 0, 0), 19 }, + { conv_key(100, 40, 24, 256, 256, 0, 0), 29 }, + { conv_key(100, 52, 30, 128, 256, 0, 0), 8 }, + { conv_key(100, 52, 30, 192, 192, 0, 0), 18 }, + { conv_key(100, 52, 30, 192, 384, 0, 0), 8 }, + { conv_key(100, 52, 30, 256, 256, 0, 0), 8 }, + { conv_key(100, 52, 30, 256, 512, 0, 0), 8 }, + { conv_key(100, 52, 30, 384, 384, 0, 0), 8 }, + { conv_key(100, 52, 30, 512, 512, 0, 0), 58 }, + { conv_key(100, 52, 30, 768, 768, 0, 0), 58 }, + { conv_key(100, 52, 32, 64, 128, 0, 0), 19 }, + { conv_key(100, 52, 32, 128, 128, 0, 0), 8 }, + { conv_key(100, 52, 32, 256, 256, 0, 0), 8 }, + { conv_key(100, 52, 32, 512, 512, 0, 0), 53 }, + { conv_key(100, 60, 34, 64, 128, 0, 0), 8 }, + { conv_key(100, 60, 34, 128, 128, 0, 0), 18 }, + { conv_key(100, 60, 34, 256, 256, 0, 0), 19 }, + { conv_key(100, 80, 45, 128, 256, 0, 0), 8 }, + { conv_key(100, 80, 45, 192, 384, 0, 0), 82 }, + { conv_key(100, 80, 45, 512, 512, 0, 0), 46 }, + { conv_key(100, 80, 45, 768, 768, 0, 0), 39 }, + { conv_key(100, 80, 48, 64, 128, 0, 0), 19 }, + { conv_key(100, 80, 48, 128, 128, 0, 0), 18 }, + { conv_key(100, 80, 48, 256, 256, 0, 0), 8 }, + { conv_key(100, 80, 48, 512, 512, 0, 0), 84 }, + { conv_key(100, 104, 60, 128, 256, 0, 0), 8 }, + { conv_key(100, 104, 60, 192, 192, 0, 0), 8 }, + { conv_key(100, 104, 60, 256, 256, 0, 0), 58 }, + { conv_key(100, 104, 60, 256, 512, 0, 0), 58 }, + { conv_key(100, 104, 60, 384, 384, 0, 0), 87 }, + { conv_key(100, 104, 60, 512, 512, 0, 0), 39 }, + { conv_key(100, 120, 68, 64, 128, 0, 0), 8 }, + { conv_key(100, 120, 68, 128, 128, 0, 0), 29 }, + { conv_key(100, 120, 68, 128, 256, 0, 0), 8 }, + { conv_key(100, 120, 68, 192, 384, 0, 0), 87 }, + { conv_key(100, 120, 68, 256, 256, 0, 0), 58 }, + { conv_key(100, 120, 68, 512, 512, 0, 0), 87 }, + { conv_key(100, 120, 68, 768, 768, 0, 0), 46 }, + { conv_key(100, 160, 90, 128, 256, 0, 0), 87 }, + { conv_key(100, 160, 90, 192, 192, 0, 0), 75 }, + { conv_key(100, 160, 90, 256, 256, 0, 0), 46 }, + { conv_key(100, 160, 90, 256, 512, 0, 0), 68 }, + { conv_key(100, 160, 90, 384, 384, 0, 0), 68 }, + { conv_key(100, 160, 90, 512, 512, 0, 0), 46 }, + { conv_key(100, 240, 135, 128, 256, 0, 0), 68 }, + { conv_key(100, 240, 135, 192, 384, 0, 0), 46 }, + { conv_key(100, 240, 135, 512, 512, 0, 0), 46 }, + { conv_key(100, 240, 135, 768, 768, 0, 0), 75 }, + { conv_key(100, 240, 136, 64, 128, 0, 0), 28 }, + { conv_key(100, 240, 136, 128, 128, 0, 0), 87 }, + { conv_key(100, 240, 136, 128, 256, 0, 0), 68 }, + { conv_key(100, 240, 136, 192, 192, 0, 0), 46 }, + { conv_key(100, 240, 136, 256, 256, 0, 0), 46 }, + { conv_key(100, 240, 136, 256, 512, 0, 0), 46 }, + { conv_key(100, 240, 136, 384, 384, 0, 0), 68 }, + { conv_key(100, 240, 136, 512, 512, 0, 0), 46 }, + { conv_key(100, 480, 270, 128, 256, 0, 0), 58 }, + { conv_key(100, 480, 270, 192, 192, 0, 0), 46 }, + { conv_key(100, 480, 270, 256, 256, 0, 0), 87 }, + { conv_key(100, 480, 270, 256, 512, 0, 0), 75 }, + { conv_key(100, 480, 270, 384, 384, 0, 0), 68 }, + { conv_key(100, 480, 270, 512, 512, 0, 0), 46 }, +#endif +}; + +at::Tensor conv1x1_bias_wsilu(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + out = out + bias.reshape({ 1, -1, 1, 1 }); + return out * at::sigmoid(out * 4.f); + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass(out_buf, feature, weight, bias); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS_WSILU, HINT_MAP_BIAS_WSILU_NAME, + C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu_chunk_add.cu b/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu_chunk_add.cu new file mode 100644 index 0000000..92bbfae --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu_chunk_add.cu @@ -0,0 +1,390 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv1x1_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_BIAS_WSILU_CHUNK_ADD_NAME = "HINT_MAP_BIAS_WSILU_CHUNK_ADD"; +std::unordered_map HINT_MAP_BIAS_WSILU_CHUNK_ADD = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 7, 4, 256, 128, 0, 0), 8 }, + { conv_key(80, 7, 4, 512, 128, 0, 0), 19 }, + { conv_key(80, 13, 8, 256, 128, 0, 0), 19 }, + { conv_key(80, 13, 8, 512, 128, 0, 0), 19 }, + { conv_key(80, 14, 8, 256, 128, 0, 0), 19 }, + { conv_key(80, 14, 8, 512, 128, 0, 0), 19 }, + { conv_key(80, 14, 8, 1024, 256, 0, 0), 8 }, + { conv_key(80, 20, 12, 256, 128, 0, 0), 19 }, + { conv_key(80, 20, 12, 512, 128, 0, 0), 19 }, + { conv_key(80, 26, 15, 512, 256, 0, 0), 8 }, + { conv_key(80, 26, 15, 768, 384, 0, 0), 8 }, + { conv_key(80, 26, 15, 2048, 512, 0, 0), 29 }, + { conv_key(80, 26, 15, 3072, 768, 0, 0), 14 }, + { conv_key(80, 26, 16, 256, 128, 0, 0), 8 }, + { conv_key(80, 26, 16, 512, 128, 0, 0), 8 }, + { conv_key(80, 26, 16, 1024, 256, 0, 0), 29 }, + { conv_key(80, 28, 16, 256, 128, 0, 0), 8 }, + { conv_key(80, 28, 16, 512, 128, 0, 0), 7 }, + { conv_key(80, 28, 16, 1024, 256, 0, 0), 29 }, + { conv_key(80, 28, 16, 2048, 512, 0, 0), 29 }, + { conv_key(80, 30, 17, 256, 128, 0, 0), 19 }, + { conv_key(80, 30, 17, 512, 128, 0, 0), 8 }, + { conv_key(80, 40, 24, 256, 128, 0, 0), 19 }, + { conv_key(80, 40, 24, 512, 128, 0, 0), 8 }, + { conv_key(80, 40, 24, 1024, 256, 0, 0), 29 }, + { conv_key(80, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(80, 52, 30, 768, 192, 0, 0), 7 }, + { conv_key(80, 52, 30, 768, 384, 0, 0), 29 }, + { conv_key(80, 52, 30, 1024, 256, 0, 0), 29 }, + { conv_key(80, 52, 30, 1024, 512, 0, 0), 15 }, + { conv_key(80, 52, 30, 1536, 384, 0, 0), 14 }, + { conv_key(80, 52, 30, 2048, 512, 0, 0), 14 }, + { conv_key(80, 52, 30, 3072, 768, 0, 0), 14 }, + { conv_key(80, 52, 32, 256, 128, 0, 0), 8 }, + { conv_key(80, 52, 32, 512, 128, 0, 0), 18 }, + { conv_key(80, 52, 32, 1024, 256, 0, 0), 14 }, + { conv_key(80, 52, 32, 2048, 512, 0, 0), 14 }, + { conv_key(80, 60, 34, 256, 128, 0, 0), 29 }, + { conv_key(80, 60, 34, 512, 128, 0, 0), 7 }, + { conv_key(80, 60, 34, 1024, 256, 0, 0), 14 }, + { conv_key(80, 80, 45, 512, 256, 0, 0), 29 }, + { conv_key(80, 80, 45, 768, 384, 0, 0), 11 }, + { conv_key(80, 80, 45, 2048, 512, 0, 0), 14 }, + { conv_key(80, 80, 45, 3072, 768, 0, 0), 14 }, + { conv_key(80, 80, 48, 256, 128, 0, 0), 7 }, + { conv_key(80, 80, 48, 512, 128, 0, 0), 7 }, + { conv_key(80, 80, 48, 1024, 256, 0, 0), 14 }, + { conv_key(80, 80, 48, 2048, 512, 0, 0), 14 }, + { conv_key(80, 104, 60, 512, 256, 0, 0), 14 }, + { conv_key(80, 104, 60, 768, 192, 0, 0), 14 }, + { conv_key(80, 104, 60, 1024, 256, 0, 0), 14 }, + { conv_key(80, 104, 60, 1024, 512, 0, 0), 14 }, + { conv_key(80, 104, 60, 1536, 384, 0, 0), 14 }, + { conv_key(80, 104, 60, 2048, 512, 0, 0), 14 }, + { conv_key(80, 120, 68, 256, 128, 0, 0), 7 }, + { conv_key(80, 120, 68, 512, 128, 0, 0), 14 }, + { conv_key(80, 120, 68, 512, 256, 0, 0), 14 }, + { conv_key(80, 120, 68, 768, 384, 0, 0), 14 }, + { conv_key(80, 120, 68, 1024, 256, 0, 0), 14 }, + { conv_key(80, 120, 68, 2048, 512, 0, 0), 14 }, + { conv_key(80, 120, 68, 3072, 768, 0, 0), 14 }, + { conv_key(80, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 768, 192, 0, 0), 14 }, + { conv_key(80, 160, 90, 1024, 256, 0, 0), 14 }, + { conv_key(80, 160, 90, 1024, 512, 0, 0), 14 }, + { conv_key(80, 160, 90, 1536, 384, 0, 0), 14 }, + { conv_key(80, 160, 90, 2048, 512, 0, 0), 14 }, + { conv_key(80, 240, 135, 512, 256, 0, 0), 14 }, + { conv_key(80, 240, 135, 768, 384, 0, 0), 14 }, + { conv_key(80, 240, 135, 2048, 512, 0, 0), 14 }, + { conv_key(80, 240, 135, 3072, 768, 0, 0), 14 }, + { conv_key(80, 240, 136, 256, 128, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 128, 0, 0), 14 }, + { conv_key(80, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 768, 192, 0, 0), 14 }, + { conv_key(80, 240, 136, 1024, 256, 0, 0), 14 }, + { conv_key(80, 240, 136, 1024, 512, 0, 0), 14 }, + { conv_key(80, 240, 136, 1536, 384, 0, 0), 14 }, + { conv_key(80, 240, 136, 2048, 512, 0, 0), 14 }, + { conv_key(80, 480, 270, 512, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 768, 192, 0, 0), 14 }, + { conv_key(80, 480, 270, 1024, 256, 0, 0), 14 }, + { conv_key(80, 480, 270, 1024, 512, 0, 0), 14 }, + { conv_key(80, 480, 270, 1536, 384, 0, 0), 14 }, + { conv_key(80, 480, 270, 2048, 512, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 7, 4, 256, 128, 0, 0), 8 }, + { conv_key(89, 7, 4, 512, 128, 0, 0), 19 }, + { conv_key(89, 13, 8, 256, 128, 0, 0), 19 }, + { conv_key(89, 13, 8, 512, 128, 0, 0), 8 }, + { conv_key(89, 14, 8, 256, 128, 0, 0), 8 }, + { conv_key(89, 14, 8, 512, 128, 0, 0), 19 }, + { conv_key(89, 14, 8, 1024, 256, 0, 0), 8 }, + { conv_key(89, 20, 12, 256, 128, 0, 0), 7 }, + { conv_key(89, 20, 12, 512, 128, 0, 0), 18 }, + { conv_key(89, 26, 15, 512, 256, 0, 0), 19 }, + { conv_key(89, 26, 15, 768, 384, 0, 0), 8 }, + { conv_key(89, 26, 15, 2048, 512, 0, 0), 29 }, + { conv_key(89, 26, 15, 3072, 768, 0, 0), 14 }, + { conv_key(89, 26, 16, 256, 128, 0, 0), 8 }, + { conv_key(89, 26, 16, 512, 128, 0, 0), 8 }, + { conv_key(89, 26, 16, 1024, 256, 0, 0), 8 }, + { conv_key(89, 28, 16, 256, 128, 0, 0), 19 }, + { conv_key(89, 28, 16, 512, 128, 0, 0), 8 }, + { conv_key(89, 28, 16, 1024, 256, 0, 0), 8 }, + { conv_key(89, 28, 16, 2048, 512, 0, 0), 18 }, + { conv_key(89, 30, 17, 256, 128, 0, 0), 8 }, + { conv_key(89, 30, 17, 512, 128, 0, 0), 8 }, + { conv_key(89, 40, 24, 256, 128, 0, 0), 8 }, + { conv_key(89, 40, 24, 512, 128, 0, 0), 8 }, + { conv_key(89, 40, 24, 1024, 256, 0, 0), 18 }, + { conv_key(89, 52, 30, 512, 256, 0, 0), 18 }, + { conv_key(89, 52, 30, 768, 192, 0, 0), 7 }, + { conv_key(89, 52, 30, 768, 384, 0, 0), 7 }, + { conv_key(89, 52, 30, 1024, 256, 0, 0), 5 }, + { conv_key(89, 52, 30, 1024, 512, 0, 0), 14 }, + { conv_key(89, 52, 30, 1536, 384, 0, 0), 14 }, + { conv_key(89, 52, 30, 2048, 512, 0, 0), 9 }, + { conv_key(89, 52, 30, 3072, 768, 0, 0), 14 }, + { conv_key(89, 52, 32, 256, 128, 0, 0), 8 }, + { conv_key(89, 52, 32, 512, 128, 0, 0), 7 }, + { conv_key(89, 52, 32, 1024, 256, 0, 0), 5 }, + { conv_key(89, 52, 32, 2048, 512, 0, 0), 14 }, + { conv_key(89, 60, 34, 256, 128, 0, 0), 19 }, + { conv_key(89, 60, 34, 512, 128, 0, 0), 7 }, + { conv_key(89, 60, 34, 1024, 256, 0, 0), 5 }, + { conv_key(89, 80, 45, 512, 256, 0, 0), 5 }, + { conv_key(89, 80, 45, 768, 384, 0, 0), 14 }, + { conv_key(89, 80, 45, 2048, 512, 0, 0), 14 }, + { conv_key(89, 80, 45, 3072, 768, 0, 0), 14 }, + { conv_key(89, 80, 48, 256, 128, 0, 0), 7 }, + { conv_key(89, 80, 48, 512, 128, 0, 0), 5 }, + { conv_key(89, 80, 48, 1024, 256, 0, 0), 10 }, + { conv_key(89, 80, 48, 2048, 512, 0, 0), 9 }, + { conv_key(89, 104, 60, 512, 256, 0, 0), 9 }, + { conv_key(89, 104, 60, 768, 192, 0, 0), 14 }, + { conv_key(89, 104, 60, 1024, 256, 0, 0), 14 }, + { conv_key(89, 104, 60, 1024, 512, 0, 0), 9 }, + { conv_key(89, 104, 60, 1536, 384, 0, 0), 14 }, + { conv_key(89, 104, 60, 2048, 512, 0, 0), 14 }, + { conv_key(89, 120, 68, 256, 128, 0, 0), 5 }, + { conv_key(89, 120, 68, 512, 128, 0, 0), 2 }, + { conv_key(89, 120, 68, 512, 256, 0, 0), 10 }, + { conv_key(89, 120, 68, 768, 384, 0, 0), 14 }, + { conv_key(89, 120, 68, 1024, 256, 0, 0), 14 }, + { conv_key(89, 120, 68, 2048, 512, 0, 0), 14 }, + { conv_key(89, 120, 68, 3072, 768, 0, 0), 14 }, + { conv_key(89, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 768, 192, 0, 0), 14 }, + { conv_key(89, 160, 90, 1024, 256, 0, 0), 14 }, + { conv_key(89, 160, 90, 1024, 512, 0, 0), 14 }, + { conv_key(89, 160, 90, 1536, 384, 0, 0), 14 }, + { conv_key(89, 160, 90, 2048, 512, 0, 0), 14 }, + { conv_key(89, 240, 135, 512, 256, 0, 0), 14 }, + { conv_key(89, 240, 135, 768, 384, 0, 0), 14 }, + { conv_key(89, 240, 135, 2048, 512, 0, 0), 14 }, + { conv_key(89, 240, 135, 3072, 768, 0, 0), 9 }, + { conv_key(89, 240, 136, 256, 128, 0, 0), 14 }, + { conv_key(89, 240, 136, 512, 128, 0, 0), 2 }, + { conv_key(89, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(89, 240, 136, 768, 192, 0, 0), 14 }, + { conv_key(89, 240, 136, 1024, 256, 0, 0), 14 }, + { conv_key(89, 240, 136, 1024, 512, 0, 0), 14 }, + { conv_key(89, 240, 136, 1536, 384, 0, 0), 14 }, + { conv_key(89, 240, 136, 2048, 512, 0, 0), 14 }, + { conv_key(89, 480, 270, 512, 256, 0, 0), 14 }, + { conv_key(89, 480, 270, 768, 192, 0, 0), 14 }, + { conv_key(89, 480, 270, 1024, 256, 0, 0), 14 }, + { conv_key(89, 480, 270, 1024, 512, 0, 0), 9 }, + { conv_key(89, 480, 270, 1536, 384, 0, 0), 14 }, + { conv_key(89, 480, 270, 2048, 512, 0, 0), 9 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 7, 4, 256, 128, 0, 0), 8 }, + { conv_key(90, 7, 4, 512, 128, 0, 0), 8 }, + { conv_key(90, 13, 8, 256, 128, 0, 0), 8 }, + { conv_key(90, 13, 8, 512, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 256, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 512, 128, 0, 0), 8 }, + { conv_key(90, 14, 8, 1024, 256, 0, 0), 8 }, + { conv_key(90, 20, 12, 256, 128, 0, 0), 8 }, + { conv_key(90, 20, 12, 512, 128, 0, 0), 8 }, + { conv_key(90, 26, 15, 512, 256, 0, 0), 8 }, + { conv_key(90, 26, 15, 768, 384, 0, 0), 8 }, + { conv_key(90, 26, 15, 2048, 512, 0, 0), 29 }, + { conv_key(90, 26, 15, 3072, 768, 0, 0), 27 }, + { conv_key(90, 26, 16, 256, 128, 0, 0), 8 }, + { conv_key(90, 26, 16, 512, 128, 0, 0), 8 }, + { conv_key(90, 26, 16, 1024, 256, 0, 0), 8 }, + { conv_key(90, 28, 16, 256, 128, 0, 0), 8 }, + { conv_key(90, 28, 16, 512, 128, 0, 0), 8 }, + { conv_key(90, 28, 16, 1024, 256, 0, 0), 8 }, + { conv_key(90, 28, 16, 2048, 512, 0, 0), 29 }, + { conv_key(90, 30, 17, 256, 128, 0, 0), 8 }, + { conv_key(90, 30, 17, 512, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 256, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 512, 128, 0, 0), 8 }, + { conv_key(90, 40, 24, 1024, 256, 0, 0), 29 }, + { conv_key(90, 52, 30, 512, 256, 0, 0), 29 }, + { conv_key(90, 52, 30, 768, 192, 0, 0), 29 }, + { conv_key(90, 52, 30, 768, 384, 0, 0), 29 }, + { conv_key(90, 52, 30, 1024, 256, 0, 0), 29 }, + { conv_key(90, 52, 30, 1024, 512, 0, 0), 29 }, + { conv_key(90, 52, 30, 1536, 384, 0, 0), 29 }, + { conv_key(90, 52, 30, 2048, 512, 0, 0), 14 }, + { conv_key(90, 52, 30, 3072, 768, 0, 0), 27 }, + { conv_key(90, 52, 32, 256, 128, 0, 0), 8 }, + { conv_key(90, 52, 32, 512, 128, 0, 0), 29 }, + { conv_key(90, 52, 32, 1024, 256, 0, 0), 29 }, + { conv_key(90, 52, 32, 2048, 512, 0, 0), 14 }, + { conv_key(90, 60, 34, 256, 128, 0, 0), 8 }, + { conv_key(90, 60, 34, 512, 128, 0, 0), 29 }, + { conv_key(90, 60, 34, 1024, 256, 0, 0), 29 }, + { conv_key(90, 80, 45, 512, 256, 0, 0), 29 }, + { conv_key(90, 80, 45, 768, 384, 0, 0), 29 }, + { conv_key(90, 80, 45, 2048, 512, 0, 0), 14 }, + { conv_key(90, 80, 45, 3072, 768, 0, 0), 27 }, + { conv_key(90, 80, 48, 256, 128, 0, 0), 29 }, + { conv_key(90, 80, 48, 512, 128, 0, 0), 29 }, + { conv_key(90, 80, 48, 1024, 256, 0, 0), 14 }, + { conv_key(90, 80, 48, 2048, 512, 0, 0), 14 }, + { conv_key(90, 104, 60, 512, 256, 0, 0), 29 }, + { conv_key(90, 104, 60, 768, 192, 0, 0), 14 }, + { conv_key(90, 104, 60, 1024, 256, 0, 0), 14 }, + { conv_key(90, 104, 60, 1024, 512, 0, 0), 14 }, + { conv_key(90, 104, 60, 1536, 384, 0, 0), 14 }, + { conv_key(90, 104, 60, 2048, 512, 0, 0), 14 }, + { conv_key(90, 120, 68, 256, 128, 0, 0), 29 }, + { conv_key(90, 120, 68, 512, 128, 0, 0), 14 }, + { conv_key(90, 120, 68, 512, 256, 0, 0), 14 }, + { conv_key(90, 120, 68, 768, 384, 0, 0), 14 }, + { conv_key(90, 120, 68, 1024, 256, 0, 0), 30 }, + { conv_key(90, 120, 68, 2048, 512, 0, 0), 27 }, + { conv_key(90, 120, 68, 3072, 768, 0, 0), 27 }, + { conv_key(90, 160, 90, 512, 256, 0, 0), 14 }, + { conv_key(90, 160, 90, 768, 192, 0, 0), 14 }, + { conv_key(90, 160, 90, 1024, 256, 0, 0), 14 }, + { conv_key(90, 160, 90, 1024, 512, 0, 0), 27 }, + { conv_key(90, 160, 90, 1536, 384, 0, 0), 14 }, + { conv_key(90, 160, 90, 2048, 512, 0, 0), 27 }, + { conv_key(90, 240, 135, 512, 256, 0, 0), 14 }, + { conv_key(90, 240, 135, 768, 384, 0, 0), 27 }, + { conv_key(90, 240, 135, 2048, 512, 0, 0), 27 }, + { conv_key(90, 240, 135, 3072, 768, 0, 0), 31 }, + { conv_key(90, 240, 136, 256, 128, 0, 0), 27 }, + { conv_key(90, 240, 136, 512, 128, 0, 0), 31 }, + { conv_key(90, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(90, 240, 136, 768, 192, 0, 0), 14 }, + { conv_key(90, 240, 136, 1024, 256, 0, 0), 14 }, + { conv_key(90, 240, 136, 1024, 512, 0, 0), 27 }, + { conv_key(90, 240, 136, 1536, 384, 0, 0), 27 }, + { conv_key(90, 240, 136, 2048, 512, 0, 0), 14 }, + { conv_key(90, 480, 270, 512, 256, 0, 0), 31 }, + { conv_key(90, 480, 270, 768, 192, 0, 0), 27 }, + { conv_key(90, 480, 270, 1024, 256, 0, 0), 31 }, + { conv_key(90, 480, 270, 1024, 512, 0, 0), 31 }, + { conv_key(90, 480, 270, 1536, 384, 0, 0), 31 }, + { conv_key(90, 480, 270, 2048, 512, 0, 0), 31 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 7, 4, 256, 128, 0, 0), 8 }, + { conv_key(100, 7, 4, 512, 128, 0, 0), 7 }, + { conv_key(100, 13, 8, 256, 128, 0, 0), 18 }, + { conv_key(100, 13, 8, 512, 128, 0, 0), 19 }, + { conv_key(100, 14, 8, 256, 128, 0, 0), 8 }, + { conv_key(100, 14, 8, 512, 128, 0, 0), 7 }, + { conv_key(100, 14, 8, 1024, 256, 0, 0), 19 }, + { conv_key(100, 20, 12, 256, 128, 0, 0), 8 }, + { conv_key(100, 20, 12, 512, 128, 0, 0), 28 }, + { conv_key(100, 26, 15, 512, 256, 0, 0), 8 }, + { conv_key(100, 26, 15, 768, 384, 0, 0), 8 }, + { conv_key(100, 26, 15, 2048, 512, 0, 0), 8 }, + { conv_key(100, 26, 15, 3072, 768, 0, 0), 8 }, + { conv_key(100, 26, 16, 256, 128, 0, 0), 19 }, + { conv_key(100, 26, 16, 512, 128, 0, 0), 19 }, + { conv_key(100, 26, 16, 1024, 256, 0, 0), 29 }, + { conv_key(100, 28, 16, 256, 128, 0, 0), 7 }, + { conv_key(100, 28, 16, 512, 128, 0, 0), 19 }, + { conv_key(100, 28, 16, 1024, 256, 0, 0), 8 }, + { conv_key(100, 28, 16, 2048, 512, 0, 0), 8 }, + { conv_key(100, 30, 17, 256, 128, 0, 0), 8 }, + { conv_key(100, 30, 17, 512, 128, 0, 0), 19 }, + { conv_key(100, 40, 24, 256, 128, 0, 0), 7 }, + { conv_key(100, 40, 24, 512, 128, 0, 0), 8 }, + { conv_key(100, 40, 24, 1024, 256, 0, 0), 8 }, + { conv_key(100, 52, 30, 512, 256, 0, 0), 8 }, + { conv_key(100, 52, 30, 768, 192, 0, 0), 29 }, + { conv_key(100, 52, 30, 768, 384, 0, 0), 8 }, + { conv_key(100, 52, 30, 1024, 256, 0, 0), 29 }, + { conv_key(100, 52, 30, 1024, 512, 0, 0), 29 }, + { conv_key(100, 52, 30, 1536, 384, 0, 0), 29 }, + { conv_key(100, 52, 30, 2048, 512, 0, 0), 29 }, + { conv_key(100, 52, 30, 3072, 768, 0, 0), 29 }, + { conv_key(100, 52, 32, 256, 128, 0, 0), 8 }, + { conv_key(100, 52, 32, 512, 128, 0, 0), 8 }, + { conv_key(100, 52, 32, 1024, 256, 0, 0), 29 }, + { conv_key(100, 52, 32, 2048, 512, 0, 0), 29 }, + { conv_key(100, 60, 34, 256, 128, 0, 0), 7 }, + { conv_key(100, 60, 34, 512, 128, 0, 0), 8 }, + { conv_key(100, 60, 34, 1024, 256, 0, 0), 29 }, + { conv_key(100, 80, 45, 512, 256, 0, 0), 29 }, + { conv_key(100, 80, 45, 768, 384, 0, 0), 29 }, + { conv_key(100, 80, 45, 2048, 512, 0, 0), 29 }, + { conv_key(100, 80, 45, 3072, 768, 0, 0), 14 }, + { conv_key(100, 80, 48, 256, 128, 0, 0), 29 }, + { conv_key(100, 80, 48, 512, 128, 0, 0), 29 }, + { conv_key(100, 80, 48, 1024, 256, 0, 0), 27 }, + { conv_key(100, 80, 48, 2048, 512, 0, 0), 29 }, + { conv_key(100, 104, 60, 512, 256, 0, 0), 29 }, + { conv_key(100, 104, 60, 768, 192, 0, 0), 27 }, + { conv_key(100, 104, 60, 1024, 256, 0, 0), 14 }, + { conv_key(100, 104, 60, 1024, 512, 0, 0), 14 }, + { conv_key(100, 104, 60, 1536, 384, 0, 0), 14 }, + { conv_key(100, 104, 60, 2048, 512, 0, 0), 14 }, + { conv_key(100, 120, 68, 256, 128, 0, 0), 29 }, + { conv_key(100, 120, 68, 512, 128, 0, 0), 27 }, + { conv_key(100, 120, 68, 512, 256, 0, 0), 27 }, + { conv_key(100, 120, 68, 768, 384, 0, 0), 14 }, + { conv_key(100, 120, 68, 1024, 256, 0, 0), 29 }, + { conv_key(100, 120, 68, 2048, 512, 0, 0), 14 }, + { conv_key(100, 120, 68, 3072, 768, 0, 0), 14 }, + { conv_key(100, 160, 90, 512, 256, 0, 0), 29 }, + { conv_key(100, 160, 90, 768, 192, 0, 0), 14 }, + { conv_key(100, 160, 90, 1024, 256, 0, 0), 14 }, + { conv_key(100, 160, 90, 1024, 512, 0, 0), 14 }, + { conv_key(100, 160, 90, 1536, 384, 0, 0), 14 }, + { conv_key(100, 160, 90, 2048, 512, 0, 0), 14 }, + { conv_key(100, 240, 135, 512, 256, 0, 0), 14 }, + { conv_key(100, 240, 135, 768, 384, 0, 0), 14 }, + { conv_key(100, 240, 135, 2048, 512, 0, 0), 14 }, + { conv_key(100, 240, 135, 3072, 768, 0, 0), 14 }, + { conv_key(100, 240, 136, 256, 128, 0, 0), 29 }, + { conv_key(100, 240, 136, 512, 128, 0, 0), 14 }, + { conv_key(100, 240, 136, 512, 256, 0, 0), 14 }, + { conv_key(100, 240, 136, 768, 192, 0, 0), 14 }, + { conv_key(100, 240, 136, 1024, 256, 0, 0), 14 }, + { conv_key(100, 240, 136, 1024, 512, 0, 0), 14 }, + { conv_key(100, 240, 136, 1536, 384, 0, 0), 14 }, + { conv_key(100, 240, 136, 2048, 512, 0, 0), 14 }, + { conv_key(100, 480, 270, 512, 256, 0, 0), 14 }, + { conv_key(100, 480, 270, 768, 192, 0, 0), 14 }, + { conv_key(100, 480, 270, 1024, 256, 0, 0), 14 }, + { conv_key(100, 480, 270, 1024, 512, 0, 0), 14 }, + { conv_key(100, 480, 270, 1536, 384, 0, 0), 14 }, + { conv_key(100, 480, 270, 2048, 512, 0, 0), 14 }, +#endif +}; + +at::Tensor conv1x1_bias_wsilu_chunk_add(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& bias, + const at::Tensor& weight0, const at::Tensor& weight1, + const at::Tensor& weight2, const at::Tensor& weight3, + const at::Tensor& bias0, const at::Tensor& bias1, + const at::Tensor& bias2, const at::Tensor& bias3, + at::Tensor& out_buf) +{ + if (sm < 75) { + auto out = at::conv2d(feature, weight); + out = out + bias.reshape({ 1, -1, 1, 1 }); + out = out * at::sigmoid(out * 4.f); + auto x1 = out.index({ at::indexing::Slice(), at::indexing::Slice(0, at::nullopt, 4), + at::indexing::Slice(), at::indexing::Slice() }); + auto x2 = out.index({ at::indexing::Slice(), at::indexing::Slice(1, at::nullopt, 4), + at::indexing::Slice(), at::indexing::Slice() }); + auto x3 = out.index({ at::indexing::Slice(), at::indexing::Slice(2, at::nullopt, 4), + at::indexing::Slice(), at::indexing::Slice() }); + auto x4 = out.index({ at::indexing::Slice(), at::indexing::Slice(3, at::nullopt, 4), + at::indexing::Slice(), at::indexing::Slice() }); + return x1 + x2 + x3 + x4; + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv1x1_bias_generic_cutlass( + out_buf, feature, weight, bias, at::nullopt, at::nullopt, at::nullopt, weight0, weight1, + weight2, weight3, bias0, bias1, bias2, bias3); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_BIAS_WSILU_CHUNK_ADD, + HINT_MAP_BIAS_WSILU_CHUNK_ADD_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu_chunk_add_kernel.h b/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu_chunk_add_kernel.h new file mode 100644 index 0000000..2081c09 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_bias_wsilu_chunk_add_kernel.h @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// clang-format off +#include +#include +#include +// clang-format on + +#include "cutlass_kernel.h" +#include "../common_cu.h" +#include "sm90_quad_gemm/sm90_builder_epilogue.h" +#include "sm90_quad_gemm/sm90_builder_mainloop.h" +#include "sm90_quad_gemm/sm90_gemm_tma_warpspecialized_cooperative_quad.h" + +#if CURRENT_DEVICE_SM == 90 +template +at::Tensor +conv1x1_bias_wsilu_chunk_add_generic_cutlass3(at::Tensor& out_buf, const at::Tensor& feature, + const at::Tensor& weight0, const at::Tensor& weight1, + const at::Tensor& weight2, const at::Tensor& weight3, + const at::Tensor& bias0, const at::Tensor& bias1, + const at::Tensor& bias2, const at::Tensor& bias3) +{ + if constexpr (std::is_same_v, cute::_256>) { + std::cerr << "conv1x1_bias_wsilu_chunk_add_generic_cutlass3: The second value of " + "Sm::TileShape cannot be cute::_256!" + << std::endl; + return at::Tensor(); + } + + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementD = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + using LayoutA = cutlass::layout::RowMajor; + using LayoutB = cutlass::layout::ColumnMajor; + using LayoutC = cutlass::layout::RowMajor; + + constexpr int AlignmentA = 128 / cutlass::sizeof_bits_v; + constexpr int AlignmentB = 128 / cutlass::sizeof_bits_v; + constexpr int AlignmentC = 128 / cutlass::sizeof_bits_v; + constexpr int AlignmentD = 128 / cutlass::sizeof_bits_v; + static constexpr auto RoundStyle = cutlass::FloatRoundStyle::round_to_nearest; + + using SmArch = typename Sm::SmArch; + using TileShape = typename Sm::TileShape; + using ClusterShape = typename Sm::ClusterShape; + using EpilogueTileType = cutlass::epilogue::collective::EpilogueTileAuto; + using EpilogueSchedule = typename Sm::EpilogueSchedule; + using KernelSchedule = typename Sm::KernelSchedule; + + using FinalEVT = cutlass::epilogue::fusion::Sm90EVT< + cutlass::epilogue::fusion::Sm90Compute, // wsilu + cutlass::epilogue::fusion::Sm90EVT< + cutlass::epilogue::fusion::Sm90Compute, // plus + cutlass::epilogue::fusion::Sm90RowBroadcast<0, TileShape, ElementC, ElementCompute>, // bias + cutlass::epilogue::fusion::Sm90AccFetch // acc + >>; + + using CollectiveEpilogue = typename QuadCollectiveBuilderEpilogue< + SmArch, cutlass::arch::OpClassTensorOp, TileShape, ClusterShape, EpilogueTileType, + ElementCompute, ElementCompute, ElementC, LayoutC, AlignmentC, ElementD, LayoutC, + AlignmentD, EpilogueSchedule, FinalEVT>::CollectiveOp; + + using CollectiveMainloop = typename QuadCollectiveBuilderMainloop< + SmArch, cutlass::arch::OpClassTensorOp, ElementA, LayoutA, AlignmentA, ElementB, LayoutB, + AlignmentB, ElementCompute, TileShape, ClusterShape, + cutlass::gemm::collective::StageCount<2>, KernelSchedule>::CollectiveOp; + + using GemmKernel = QuadGemmUniversal, // Indicates ProblemShape + CollectiveMainloop, CollectiveEpilogue>; + + using Gemm = cutlass::gemm::device::GemmUniversalAdapter; + + const int B = feature.size(0); + const int C1 = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight0.size(0); + const int C1_ = weight0.size(1); + const int KH_ = weight0.size(2); + const int KW_ = weight0.size(3); + assert(C1 == C1_ && KH_ == 1 && KW_ == 1); + assert(weight0.sizes() == weight1.sizes()); + assert(weight0.sizes() == weight2.sizes()); + assert(weight0.sizes() == weight3.sizes()); + assert(bias0.sizes() == bias1.sizes()); + assert(bias0.sizes() == bias2.sizes()); + assert(bias0.sizes() == bias3.sizes()); + const int M = H * W; + const int N = C2; + const int K = C1; + const typename GemmKernel::ProblemShape problem_size{ M, N, K, 1 }; + + // Note: It is assumed that the 4 weights are interleaved splits of a contiguous weight. + typename Gemm::Arguments args{ + cutlass::gemm::GemmUniversalMode::kGemm, + problem_size, + { static_cast(feature.data_ptr()), + cute::Stride{ feature.stride(3), cute::_1{}, 0 }, + static_cast(weight0.data_ptr()), static_cast(weight1.data_ptr()), + static_cast(weight2.data_ptr()), static_cast(weight3.data_ptr()), + cute::Stride{ weight0.stride(3) * 4, cute::_1{}, 0 } }, + { {}, + {}, + {}, + {}, // epilogue arguments, updated later + nullptr, + cute::Stride{ 0, cute::_1{}, 0 }, + static_cast(out_buf.data_ptr()), + cute::Stride{ out_buf.stride(3), cute::_1{}, 0 } }, + }; + + args.epilogue.thread0 = { + { + { static_cast(bias0.data_ptr()) }, // bias + {}, // acc + {} // plus + }, + {} // WSiLU + }; + args.epilogue.thread1 = { + { + { static_cast(bias1.data_ptr()) }, // bias + {}, // acc + {} // plus + }, + {} // WSiLU + }; + args.epilogue.thread2 = { + { + { static_cast(bias2.data_ptr()) }, // bias + {}, // acc + {} // plus + }, + {} // WSiLU + }; + args.epilogue.thread3 = { + { + { static_cast(bias3.data_ptr()) }, // bias + {}, // acc + {} // plus + }, + {} // WSiLU + }; + + args.scheduler.max_swizzle_size = 1; + args.scheduler.raster_order = + cutlass::gemm::kernel::detail::PersistentTileSchedulerSm90Params::RasterOrderOptions::Heuristic; + + Gemm gemm_op; + cutlass::Status status = gemm_op.can_implement(args); + if (status != cutlass::Status::kSuccess) { + std::cerr << "GEMM cannot implement: " << cutlass::cutlassGetStatusString(status) << std::endl; + return at::Tensor(); + } + + auto stream = at::cuda::getCurrentCUDAStream(); + status = gemm_op(args, nullptr, stream, /* cuda_adapter */ nullptr, /* launch_with_pdl */ true); + if (status != cutlass::Status::kSuccess) { + std::cerr << "GEMM failed: " << cutlass::cutlassGetStatusString(status) << std::endl; + return at::Tensor(); + } + + return out_buf; +} +#endif diff --git a/src/layers/extensions/inference/cutlass/conv1x1_kernel.h b/src/layers/extensions/inference/cutlass/conv1x1_kernel.h new file mode 100644 index 0000000..893c7c1 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv1x1_kernel.h @@ -0,0 +1,435 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +#include +#include +#include +#include +// clang-format on + +#include "conv1x1_bias_wsilu_chunk_add_kernel.h" +#include "cutlass_epilogue.h" +#include "cutlass_kernel.h" +#include "../common_cu.h" +#include "../cutlass_helper_gemm.h" +#include "../def_cutlass.h" + +template +at::Tensor conv1x1_bias_generic_cutlass2(at::Tensor& out_buf, const at::Tensor& feature, + const at::Tensor& weight, const at::optional& bias, + const at::optional& shortcut1, + const at::optional& shortcut2, + const at::optional& quant) +{ + constexpr int NumAdditionalInput = NumShortcuts + (WithQuant ? 1 : 0); + static_assert(NumAdditionalInput <= 2); + using EpilogueOp = + LinearCombination, + 128 / cutlass::sizeof_bits_v>; + + using Gemm = CustomGemmUniversalWithBroadcast< + cutlass::half_t, cutlass::layout::RowMajor, cutlass::half_t, cutlass::layout::ColumnMajor, + cutlass::half_t, cutlass::layout::RowMajor, cutlass::half_t, cutlass::arch::OpClassTensorOp, + typename Sm::SmArch, typename Sm::ShapeThreadBlock, typename Sm::ShapeWarp, typename Sm::ShapeOp, + EpilogueOp, cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<8>, Sm::Stages>; + + const int B = feature.size(0); + const int C1 = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1_ = weight.size(1); + const int KH_ = weight.size(2); + const int KW_ = weight.size(3); + assert(C1 == C1_ && KH_ == 1 && KW_ == 1); + const int M = H * W; + const int N = C2; + const int K = C1; + const cutlass::gemm::GemmCoord problem_size(M, N, K); + + void* additional_input1_ptr = nullptr; + void* additional_input2_ptr = nullptr; + int additional_input1_stride = 0; + int additional_input2_stride = 0; + if constexpr (NumAdditionalInput == 1) { + if constexpr (WithQuant) { + additional_input1_ptr = quant.value().data_ptr(); + additional_input1_stride = 0; + } else { + additional_input1_ptr = shortcut1.value().data_ptr(); + additional_input1_stride = shortcut1.value().stride(3); + } + } + if constexpr (NumAdditionalInput == 2) { + additional_input1_ptr = shortcut1.value().data_ptr(); + additional_input1_stride = shortcut1.value().stride(3); + if constexpr (WithQuant) { + additional_input2_ptr = quant.value().data_ptr(); + additional_input2_stride = 0; + } else { + additional_input2_ptr = shortcut2.value().data_ptr(); + additional_input2_stride = shortcut2.value().stride(3); + } + } + + // Note: the following tensors may be part of a pre-allocated tensor of shape [B, C1 + C2, H, W], channels_last. + typename Gemm::Arguments args; + if constexpr (NumAdditionalInput < 2) { + args = { + cutlass::gemm::GemmUniversalMode::kGemm, + problem_size, + 1, // int batch_count + {}, // args for epilogue + feature.data_ptr(), + weight.data_ptr(), + additional_input1_ptr, + ChunkAdd ? nullptr : out_buf.data_ptr(), + WithBias ? bias.value().data_ptr() : nullptr, + ChunkAdd ? out_buf.data_ptr() : nullptr, // pointer of 2nd output + 0, // int64_t batch_stride_A + 0, // int64_t batch_stride_B + 0, // int64_t batch_stride_C (shortcut) + 0, // int64_t batch_stride_D + 0, // int64_t batch_stride_Vector (bias) + 0, // int64_t batch_stride_Tensor (2nd output) + feature.stride(3), // typename LayoutA::Stride::Index lda + weight.stride(3), // typename LayoutB::Stride::Index ldb + additional_input1_stride, + ChunkAdd ? 0 : out_buf.stride(3), // typename LayoutC::Stride::Index ldd + 0, // typename LayoutC::Stride::Index ldr (bias) + ChunkAdd ? out_buf.stride(3) * 4 : 0 // typename LayoutC::Stride::Index ldt (2nd output) + }; + } else if constexpr (NumAdditionalInput == 2) { + args = { + cutlass::gemm::GemmUniversalMode::kGemm, + problem_size, + 1, // int batch_count + {}, // args for epilogue + feature.data_ptr(), + weight.data_ptr(), + additional_input1_ptr, + additional_input2_ptr, + ChunkAdd ? nullptr : out_buf.data_ptr(), + WithBias ? bias.value().data_ptr() : nullptr, + ChunkAdd ? out_buf.data_ptr() : nullptr, // pointer of 2nd output + 0, // int64_t batch_stride_A + 0, // int64_t batch_stride_B + 0, // int64_t batch_stride_C1 (shortcut1) + 0, // int64_t batch_stride_C2 (shortcut2) + 0, // int64_t batch_stride_D + 0, // int64_t batch_stride_Vector (bias) + 0, // int64_t batch_stride_Tensor (2nd output) + feature.stride(3), // typename LayoutA::Stride::Index lda + weight.stride(3), // typename LayoutB::Stride::Index ldb + additional_input1_stride, + additional_input2_stride, + ChunkAdd ? 0 : out_buf.stride(3), // typename LayoutC::Stride::Index ldd + 0, // typename LayoutC::Stride::Index ldr (bias) + ChunkAdd ? out_buf.stride(3) : 0 // typename LayoutC::Stride::Index ldt (2nd output) + }; + } else { + assert(false); + } + + Gemm gemm_op; + cutlass::Status status = gemm_op.can_implement(args); + if (status != cutlass::Status::kSuccess) { + std::cerr << "GEMM cannot implement: " << cutlass::cutlassGetStatusString(status) << std::endl; + return at::Tensor(); + } + + auto stream = at::cuda::getCurrentCUDAStream(); + status = gemm_op(args, nullptr, stream); + if (status != cutlass::Status::kSuccess) { + std::cerr << "GEMM failed: " << cutlass::cutlassGetStatusString(status) << std::endl; + return at::Tensor(); + } + + return out_buf; +} + +#if CURRENT_DEVICE_SM == 90 || CURRENT_DEVICE_SM == 100 +template +at::Tensor conv1x1_bias_generic_cutlass3(at::Tensor& out_buf, const at::Tensor& feature, + const at::Tensor& weight, const at::optional& bias, + const at::optional& shortcut1, + const at::optional& shortcut2, + const at::optional& quant) +{ + static_assert(!ChunkAdd); + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementD = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + using LayoutA = cutlass::layout::RowMajor; + using LayoutB = cutlass::layout::ColumnMajor; + using LayoutC = cutlass::layout::RowMajor; + + static constexpr int AlignmentA = 128 / cutlass::sizeof_bits_v; + static constexpr int AlignmentB = 128 / cutlass::sizeof_bits_v; + static constexpr int AlignmentC = 128 / cutlass::sizeof_bits_v; + static constexpr int AlignmentD = 128 / cutlass::sizeof_bits_v; + static constexpr auto RoundStyle = cutlass::FloatRoundStyle::round_to_nearest; + + using SmArch = typename Sm::SmArch; + using TileShape = typename Sm::TileShape; + using ClusterShape = typename Sm::ClusterShape; + using EpilogueTileType = cutlass::epilogue::collective::EpilogueTileAuto; + using EpilogueSchedule = typename Sm::EpilogueSchedule; + using KernelSchedule = typename Sm::KernelSchedule; + + using GmemStrideTypeC = cutlass::detail::TagToStrideC_t; + using EpilogueDescriptor = std::conditional_t< + std::is_same_v, + cutlass::epilogue::collective::detail::EpilogueDescriptor, + cutlass::epilogue::collective::detail::Sm100EpilogueDescriptor< + cutlass::arch::OpClassTensorOp, TileShape, EpilogueTileType, ElementCompute, ElementC, + ElementD, EpilogueSchedule, GmemStrideTypeC, GmemStrideTypeC, false, false>>; + using AuxLoadDescriptor = std::conditional_t< + std::is_same_v, + cutlass::epilogue::collective::detail::AuxLoadDescriptor, + cutlass::epilogue::collective::detail::Sm100AuxLoadDescriptor>; + using AuxLoad = cutlass::epilogue::fusion::Sm90AuxLoad< + AuxLoadDescriptor::Stages, typename AuxLoadDescriptor::EpilogueTile, + typename AuxLoadDescriptor::Element, typename AuxLoadDescriptor::Stride, + typename AuxLoadDescriptor::SmemLayoutAtom, typename AuxLoadDescriptor::CopyOpS2R>; + + using AccEVT = cutlass::epilogue::fusion::Sm90AccFetch; + + using BiasEVT = std::conditional_t< + WithBias, + cutlass::epilogue::fusion::Sm90EVT< + cutlass::epilogue::fusion::Sm90Compute, // plus + cutlass::epilogue::fusion::Sm90RowBroadcast<0, TileShape, ElementC, ElementCompute>, // bias + AccEVT // acc + >, + AccEVT>; + + using Shortcut1EVT = std::conditional_t< + NumShortcuts >= 1, + cutlass::epilogue::fusion::Sm90EVT< + cutlass::epilogue::fusion::Sm90Compute, // plus + cutlass::epilogue::fusion::Sm90SrcFetch, // shortcut1 + BiasEVT // acc + bias + >, + BiasEVT>; + + using Shortcut2EVT = std::conditional_t< + NumShortcuts == 2, + cutlass::epilogue::fusion::Sm90EVT< + cutlass::epilogue::fusion::Sm90Compute, // plus + AuxLoad, // shortcut2 + Shortcut1EVT // acc + bias + shortcut1 + >, + Shortcut1EVT>; + + using QuantEVT = std::conditional_t< + WithQuant, + cutlass::epilogue::fusion::Sm90EVT< + cutlass::epilogue::fusion::Sm90Compute, // multiply + cutlass::epilogue::fusion::Sm90RowBroadcast<0, TileShape, ElementC, ElementCompute>, // quant + Shortcut2EVT // acc + bias + shortcut1 + shortcut2 + >, + Shortcut2EVT>; + + using FinalEVT = std::conditional_t< + WSiLU, + cutlass::epilogue::fusion::Sm90EVT, // wsilu + QuantEVT // previous + >, + QuantEVT>; + + using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder< + SmArch, cutlass::arch::OpClassTensorOp, TileShape, ClusterShape, EpilogueTileType, + ElementCompute, ElementCompute, ElementC, LayoutC, AlignmentC, ElementD, LayoutC, + AlignmentD, EpilogueSchedule, FinalEVT>::CollectiveOp; + + using CollectiveMainloop = typename cutlass::gemm::collective::CollectiveBuilder< + SmArch, cutlass::arch::OpClassTensorOp, ElementA, LayoutA, AlignmentA, ElementB, LayoutB, + AlignmentB, ElementCompute, TileShape, ClusterShape, + cutlass::gemm::collective::StageCountAutoCarveout( + sizeof(typename CollectiveEpilogue::SharedStorage))>, + KernelSchedule>::CollectiveOp; + + using GemmKernel = + cutlass::gemm::kernel::GemmUniversal, // Indicates ProblemShape + CollectiveMainloop, CollectiveEpilogue>; + + using Gemm = cutlass::gemm::device::GemmUniversalAdapter; + + const int B = feature.size(0); + const int C1 = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1_ = weight.size(1); + const int KH_ = weight.size(2); + const int KW_ = weight.size(3); + assert(C1 == C1_ && KH_ == 1 && KW_ == 1); + const int M = H * W; + const int N = C2; + const int K = C1; + const typename GemmKernel::ProblemShape problem_size{ M, N, K, 1 }; + + // Note: the following tensors may be part of a pre-allocated tensor of shape [B, C1 + C2, H, W], channels_last. + typename Gemm::Arguments args{ + cutlass::gemm::GemmUniversalMode::kGemm, + problem_size, + { static_cast(feature.data_ptr()), + cute::Stride{ feature.stride(3), cute::_1{}, 0 }, + static_cast(weight.data_ptr()), + cute::Stride{ weight.stride(3), cute::_1{}, 0 } }, + { {}, // epilogue arguments, updated later + shortcut1.has_value() ? static_cast(shortcut1.value().data_ptr()) : nullptr, + cute::Stride{ + shortcut1.has_value() ? shortcut1.value().stride(3) : 0, cute::_1{}, 0 }, + static_cast(out_buf.data_ptr()), + cute::Stride{ out_buf.stride(3), cute::_1{}, 0 } }, + }; + + typename AccEVT::Arguments acc_args = {}; + typename BiasEVT::Arguments bias_args; + + if constexpr (WithBias) { + bias_args = { + { static_cast(bias.value().data_ptr()) }, // bias + acc_args, // acc + {} // plus + }; + } else { + bias_args = acc_args; + } + + typename Shortcut1EVT::Arguments shortcut1_args; + + if constexpr (NumShortcuts >= 1) { + shortcut1_args = { + {}, // shortcut1 + bias_args, // acc + bias + {} // plus + }; + } else { + shortcut1_args = bias_args; + } + + typename Shortcut2EVT::Arguments shortcut2_args; + + if constexpr (NumShortcuts == 2) { + shortcut2_args = { + { + static_cast(shortcut2.value().data_ptr()), // ptr + static_cast(0), // null_default + cute::Stride{ shortcut2.value().stride(3), cute::_1{}, 0 } // stride + }, // shortcut2 + shortcut1_args, // acc + bias + shortcut1 + {} // plus + }; + } else { + shortcut2_args = shortcut1_args; + } + + typename QuantEVT::Arguments quant_args; + + if constexpr (WithQuant) { + quant_args = { + { + static_cast(quant.value().data_ptr()), // ptr + static_cast(1) // null_default + }, // quant + shortcut2_args, // acc + bias + shortcut1 + shortcut2 + {} // multiply + }; + } else { + quant_args = shortcut2_args; + } + + typename FinalEVT::Arguments final_args; + + if constexpr (WSiLU) { + final_args = { + quant_args, // previous + {} // wsilu + }; + } else { + final_args = quant_args; + } + + args.epilogue.thread = final_args; + + args.scheduler.max_swizzle_size = 1; + args.scheduler.raster_order = + cutlass::gemm::kernel::detail::PersistentTileSchedulerSm90Params::RasterOrderOptions::Heuristic; + + Gemm gemm_op; + cutlass::Status status = gemm_op.can_implement(args); + if (status != cutlass::Status::kSuccess) { + std::cerr << "GEMM cannot implement: " << cutlass::cutlassGetStatusString(status) << std::endl; + return at::Tensor(); + } + + auto stream = at::cuda::getCurrentCUDAStream(); + status = gemm_op(args, nullptr, stream, /* cuda_adapter */ nullptr, /* launch_with_pdl */ true); + if (status != cutlass::Status::kSuccess) { + std::cerr << "GEMM failed: " << cutlass::cutlassGetStatusString(status) << std::endl; + return at::Tensor(); + } + + return out_buf; +} +#endif + +template +at::Tensor conv1x1_bias_generic_cutlass(at::Tensor& out_buf, const at::Tensor& feature, + const at::Tensor& weight, + const at::optional& bias = at::nullopt, + const at::optional& shortcut1 = at::nullopt, + const at::optional& shortcut2 = at::nullopt, + const at::optional& quant = at::nullopt, + const at::optional& weight0 = at::nullopt, + const at::optional& weight1 = at::nullopt, + const at::optional& weight2 = at::nullopt, + const at::optional& weight3 = at::nullopt, + const at::optional& bias0 = at::nullopt, + const at::optional& bias1 = at::nullopt, + const at::optional& bias2 = at::nullopt, + const at::optional& bias3 = at::nullopt) +{ + if constexpr (std::is_same_v) { +#if CURRENT_DEVICE_SM == 90 + if constexpr (ChunkAdd) { + return conv1x1_bias_wsilu_chunk_add_generic_cutlass3( + out_buf, feature, weight0.value(), weight1.value(), weight2.value(), + weight3.value(), bias0.value(), bias1.value(), bias2.value(), bias3.value()); + } else { + return conv1x1_bias_generic_cutlass3( + out_buf, feature, weight, bias, shortcut1, shortcut2, quant); + } +#else + return at::Tensor(); +#endif + } else if constexpr (std::is_same_v) { +#if CURRENT_DEVICE_SM == 100 + if constexpr (ChunkAdd) { + return at::Tensor(); + } else { + return conv1x1_bias_generic_cutlass3( + out_buf, feature, weight, bias, shortcut1, shortcut2, quant); + } +#else + return at::Tensor(); +#endif + } else { + return conv1x1_bias_generic_cutlass2( + out_buf, feature, weight, bias, shortcut1, shortcut2, quant); + } +} diff --git a/src/layers/extensions/inference/cutlass/conv_bias.cu b/src/layers/extensions/inference/cutlass/conv_bias.cu new file mode 100644 index 0000000..c784cde --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv_bias.cu @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "conv_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_CONV_BIAS_NAME = "HINT_MAP_CONV_BIAS"; +std::unordered_map HINT_MAP_CONV_BIAS = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 14, 8, 128, 128, 1, 0), 19 }, { conv_key(80, 14, 8, 128, 256, 1, 0), 8 }, + { conv_key(80, 26, 16, 128, 128, 1, 0), 8 }, { conv_key(80, 26, 16, 128, 256, 1, 0), 8 }, + { conv_key(80, 28, 16, 128, 128, 1, 0), 8 }, { conv_key(80, 28, 16, 256, 256, 1, 0), 8 }, + { conv_key(80, 40, 24, 128, 128, 1, 0), 8 }, { conv_key(80, 40, 24, 128, 256, 1, 0), 8 }, + { conv_key(80, 52, 30, 128, 256, 1, 1), 8 }, { conv_key(80, 52, 30, 256, 256, 1, 0), 8 }, + { conv_key(80, 52, 30, 256, 384, 1, 1), 8 }, { conv_key(80, 52, 30, 256, 512, 1, 1), 8 }, + { conv_key(80, 52, 30, 512, 512, 1, 0), 8 }, { conv_key(80, 52, 32, 128, 128, 1, 0), 19 }, + { conv_key(80, 52, 32, 256, 256, 1, 0), 8 }, { conv_key(80, 60, 34, 128, 128, 1, 0), 8 }, + { conv_key(80, 60, 34, 128, 256, 1, 0), 8 }, { conv_key(80, 80, 45, 2048, 256, 0, 1), 14 }, + { conv_key(80, 80, 48, 128, 128, 1, 0), 8 }, { conv_key(80, 80, 48, 256, 256, 1, 0), 8 }, + { conv_key(80, 104, 60, 128, 256, 1, 1), 8 }, { conv_key(80, 104, 60, 256, 256, 1, 0), 8 }, + { conv_key(80, 104, 60, 256, 384, 1, 1), 8 }, { conv_key(80, 104, 60, 256, 512, 1, 1), 8 }, + { conv_key(80, 104, 60, 512, 512, 1, 0), 29 }, { conv_key(80, 120, 68, 128, 128, 1, 0), 8 }, + { conv_key(80, 120, 68, 128, 256, 1, 0), 8 }, { conv_key(80, 120, 68, 256, 256, 1, 0), 29 }, + { conv_key(80, 120, 68, 2048, 256, 0, 1), 9 }, { conv_key(80, 160, 90, 128, 256, 1, 1), 29 }, + { conv_key(80, 160, 90, 256, 256, 1, 0), 14 }, { conv_key(80, 160, 90, 256, 384, 1, 1), 24 }, + { conv_key(80, 160, 90, 256, 512, 1, 1), 24 }, { conv_key(80, 160, 90, 512, 512, 1, 0), 29 }, + { conv_key(80, 240, 135, 2048, 256, 0, 1), 9 }, { conv_key(80, 240, 136, 128, 128, 1, 0), 15 }, + { conv_key(80, 240, 136, 128, 256, 1, 1), 27 }, { conv_key(80, 240, 136, 256, 256, 1, 0), 10 }, + { conv_key(80, 240, 136, 256, 384, 1, 1), 10 }, { conv_key(80, 240, 136, 256, 512, 1, 1), 29 }, + { conv_key(80, 240, 136, 512, 512, 1, 0), 24 }, { conv_key(80, 480, 270, 128, 256, 1, 1), 24 }, + { conv_key(80, 480, 270, 256, 256, 1, 0), 24 }, { conv_key(80, 480, 270, 256, 384, 1, 1), 24 }, + { conv_key(80, 480, 270, 256, 512, 1, 1), 24 }, { conv_key(80, 480, 270, 512, 512, 1, 0), 20 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 14, 8, 128, 128, 1, 0), 8 }, { conv_key(89, 14, 8, 128, 256, 1, 0), 8 }, + { conv_key(89, 26, 16, 128, 128, 1, 0), 8 }, { conv_key(89, 26, 16, 128, 256, 1, 0), 8 }, + { conv_key(89, 28, 16, 128, 128, 1, 0), 8 }, { conv_key(89, 28, 16, 256, 256, 1, 0), 8 }, + { conv_key(89, 40, 24, 128, 128, 1, 0), 8 }, { conv_key(89, 40, 24, 128, 256, 1, 0), 8 }, + { conv_key(89, 52, 30, 128, 256, 1, 1), 8 }, { conv_key(89, 52, 30, 256, 256, 1, 0), 8 }, + { conv_key(89, 52, 30, 256, 384, 1, 1), 8 }, { conv_key(89, 52, 30, 256, 512, 1, 1), 8 }, + { conv_key(89, 52, 30, 512, 512, 1, 0), 8 }, { conv_key(89, 52, 32, 128, 128, 1, 0), 8 }, + { conv_key(89, 52, 32, 256, 256, 1, 0), 8 }, { conv_key(89, 60, 34, 128, 128, 1, 0), 8 }, + { conv_key(89, 60, 34, 128, 256, 1, 0), 8 }, { conv_key(89, 80, 45, 2048, 256, 0, 1), 0 }, + { conv_key(89, 80, 48, 128, 128, 1, 0), 8 }, { conv_key(89, 80, 48, 256, 256, 1, 0), 8 }, + { conv_key(89, 104, 60, 128, 256, 1, 1), 8 }, { conv_key(89, 104, 60, 256, 256, 1, 0), 8 }, + { conv_key(89, 104, 60, 256, 384, 1, 1), 8 }, { conv_key(89, 104, 60, 256, 512, 1, 1), 8 }, + { conv_key(89, 104, 60, 512, 512, 1, 0), 28 }, { conv_key(89, 120, 68, 128, 128, 1, 0), 8 }, + { conv_key(89, 120, 68, 128, 256, 1, 0), 8 }, { conv_key(89, 120, 68, 256, 256, 1, 0), 18 }, + { conv_key(89, 120, 68, 2048, 256, 0, 1), 14 }, { conv_key(89, 160, 90, 128, 256, 1, 1), 8 }, + { conv_key(89, 160, 90, 256, 256, 1, 0), 28 }, { conv_key(89, 160, 90, 256, 384, 1, 1), 29 }, + { conv_key(89, 160, 90, 256, 512, 1, 1), 18 }, { conv_key(89, 160, 90, 512, 512, 1, 0), 14 }, + { conv_key(89, 240, 135, 2048, 256, 0, 1), 10 }, { conv_key(89, 240, 136, 128, 128, 1, 0), 28 }, + { conv_key(89, 240, 136, 128, 256, 1, 1), 18 }, { conv_key(89, 240, 136, 256, 256, 1, 0), 27 }, + { conv_key(89, 240, 136, 256, 384, 1, 1), 27 }, { conv_key(89, 240, 136, 256, 512, 1, 1), 14 }, + { conv_key(89, 240, 136, 512, 512, 1, 0), 10 }, { conv_key(89, 480, 270, 128, 256, 1, 1), 9 }, + { conv_key(89, 480, 270, 256, 256, 1, 0), 14 }, { conv_key(89, 480, 270, 256, 384, 1, 1), 10 }, + { conv_key(89, 480, 270, 256, 512, 1, 1), 9 }, { conv_key(89, 480, 270, 512, 512, 1, 0), 9 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 14, 8, 128, 128, 1, 0), 8 }, { conv_key(90, 14, 8, 128, 256, 1, 0), 8 }, + { conv_key(90, 26, 16, 128, 128, 1, 0), 8 }, { conv_key(90, 26, 16, 128, 256, 1, 0), 8 }, + { conv_key(90, 28, 16, 128, 128, 1, 0), 8 }, { conv_key(90, 28, 16, 256, 256, 1, 0), 8 }, + { conv_key(90, 40, 24, 128, 128, 1, 0), 8 }, { conv_key(90, 40, 24, 128, 256, 1, 0), 8 }, + { conv_key(90, 52, 30, 128, 256, 1, 1), 8 }, { conv_key(90, 52, 30, 256, 256, 1, 0), 8 }, + { conv_key(90, 52, 30, 256, 384, 1, 1), 8 }, { conv_key(90, 52, 30, 256, 512, 1, 1), 8 }, + { conv_key(90, 52, 30, 512, 512, 1, 0), 8 }, { conv_key(90, 52, 32, 128, 128, 1, 0), 8 }, + { conv_key(90, 52, 32, 256, 256, 1, 0), 8 }, { conv_key(90, 60, 34, 128, 128, 1, 0), 8 }, + { conv_key(90, 60, 34, 128, 256, 1, 0), 8 }, { conv_key(90, 80, 45, 2048, 256, 0, 1), 9 }, + { conv_key(90, 80, 48, 128, 128, 1, 0), 8 }, { conv_key(90, 80, 48, 256, 256, 1, 0), 8 }, + { conv_key(90, 104, 60, 128, 256, 1, 1), 8 }, { conv_key(90, 104, 60, 256, 256, 1, 0), 8 }, + { conv_key(90, 104, 60, 256, 384, 1, 1), 8 }, { conv_key(90, 104, 60, 256, 512, 1, 1), 8 }, + { conv_key(90, 104, 60, 512, 512, 1, 0), 29 }, { conv_key(90, 120, 68, 128, 128, 1, 0), 8 }, + { conv_key(90, 120, 68, 128, 256, 1, 0), 8 }, { conv_key(90, 120, 68, 256, 256, 1, 0), 8 }, + { conv_key(90, 120, 68, 2048, 256, 0, 1), 21 }, { conv_key(90, 160, 90, 128, 256, 1, 1), 8 }, + { conv_key(90, 160, 90, 256, 256, 1, 0), 29 }, { conv_key(90, 160, 90, 256, 384, 1, 1), 29 }, + { conv_key(90, 160, 90, 256, 512, 1, 1), 29 }, { conv_key(90, 160, 90, 512, 512, 1, 0), 27 }, + { conv_key(90, 240, 135, 2048, 256, 0, 1), 21 }, { conv_key(90, 240, 136, 128, 128, 1, 0), 29 }, + { conv_key(90, 240, 136, 128, 256, 1, 1), 29 }, { conv_key(90, 240, 136, 256, 256, 1, 0), 27 }, + { conv_key(90, 240, 136, 256, 384, 1, 1), 24 }, { conv_key(90, 240, 136, 256, 512, 1, 1), 24 }, + { conv_key(90, 240, 136, 512, 512, 1, 0), 21 }, { conv_key(90, 480, 270, 128, 256, 1, 1), 27 }, + { conv_key(90, 480, 270, 256, 256, 1, 0), 21 }, { conv_key(90, 480, 270, 256, 384, 1, 1), 21 }, + { conv_key(90, 480, 270, 256, 512, 1, 1), 21 }, { conv_key(90, 480, 270, 512, 512, 1, 0), 20 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 14, 8, 128, 128, 1, 0), 8 }, + { conv_key(100, 14, 8, 128, 256, 1, 0), 8 }, + { conv_key(100, 26, 16, 128, 128, 1, 0), 8 }, + { conv_key(100, 26, 16, 128, 256, 1, 0), 8 }, + { conv_key(100, 28, 16, 128, 128, 1, 0), 8 }, + { conv_key(100, 28, 16, 256, 256, 1, 0), 8 }, + { conv_key(100, 40, 24, 128, 128, 1, 0), 8 }, + { conv_key(100, 40, 24, 128, 256, 1, 0), 8 }, + { conv_key(100, 52, 30, 128, 256, 1, 1), 8 }, + { conv_key(100, 52, 30, 256, 256, 1, 0), 8 }, + { conv_key(100, 52, 30, 256, 384, 1, 1), 8 }, + { conv_key(100, 52, 30, 256, 512, 1, 1), 8 }, + { conv_key(100, 52, 30, 512, 512, 1, 0), 8 }, + { conv_key(100, 52, 32, 128, 128, 1, 0), 19 }, + { conv_key(100, 52, 32, 256, 256, 1, 0), 8 }, + { conv_key(100, 60, 34, 128, 128, 1, 0), 8 }, + { conv_key(100, 60, 34, 128, 256, 1, 0), 8 }, + { conv_key(100, 80, 45, 2048, 256, 0, 1), 29 }, + { conv_key(100, 80, 48, 128, 128, 1, 0), 8 }, + { conv_key(100, 80, 48, 256, 256, 1, 0), 8 }, + { conv_key(100, 104, 60, 128, 256, 1, 1), 8 }, + { conv_key(100, 104, 60, 256, 256, 1, 0), 8 }, + { conv_key(100, 104, 60, 256, 384, 1, 1), 8 }, + { conv_key(100, 104, 60, 256, 512, 1, 1), 8 }, + { conv_key(100, 104, 60, 512, 512, 1, 0), 29 }, + { conv_key(100, 120, 68, 128, 128, 1, 0), 19 }, + { conv_key(100, 120, 68, 128, 256, 1, 0), 8 }, + { conv_key(100, 120, 68, 256, 256, 1, 0), 8 }, + { conv_key(100, 120, 68, 2048, 256, 0, 1), 27 }, + { conv_key(100, 160, 90, 128, 256, 1, 1), 8 }, + { conv_key(100, 160, 90, 256, 256, 1, 0), 29 }, + { conv_key(100, 160, 90, 256, 384, 1, 1), 29 }, + { conv_key(100, 160, 90, 256, 512, 1, 1), 29 }, + { conv_key(100, 160, 90, 512, 512, 1, 0), 27 }, + { conv_key(100, 240, 135, 2048, 256, 0, 1), 14 }, + { conv_key(100, 240, 136, 128, 128, 1, 0), 29 }, + { conv_key(100, 240, 136, 128, 256, 1, 1), 29 }, + { conv_key(100, 240, 136, 256, 256, 1, 0), 27 }, + { conv_key(100, 240, 136, 256, 384, 1, 1), 27 }, + { conv_key(100, 240, 136, 256, 512, 1, 1), 27 }, + { conv_key(100, 240, 136, 512, 512, 1, 0), 21 }, + { conv_key(100, 480, 270, 128, 256, 1, 1), 9 }, + { conv_key(100, 480, 270, 256, 256, 1, 0), 27 }, + { conv_key(100, 480, 270, 256, 384, 1, 1), 29 }, + { conv_key(100, 480, 270, 256, 512, 1, 1), 29 }, + { conv_key(100, 480, 270, 512, 512, 1, 0), 27 }, +#endif +}; + +at::Tensor conv_bias(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const int stride, at::Tensor& out_buf) +{ + const int kernel = weight.size(2); + if (sm < 75) { + auto out = at::conv2d(feature, weight, at::nullopt, stride, (kernel - 1) / 2); + return out + bias.reshape({ 1, -1, 1, 1 }); + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return conv_bias_generic_cutlass(out_buf, feature, weight, bias, stride); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + assert(kernel >= 2 && kernel <= 3 && stride >= 1 && stride <= 2); + return launch_cutlass_helper(sm, launch_cutlass, HINT_MAP_CONV_BIAS, + HINT_MAP_CONV_BIAS_NAME, C2, C1, H, + W, kernel - 2, stride - 1); +} diff --git a/src/layers/extensions/inference/cutlass/conv_kernel.h b/src/layers/extensions/inference/cutlass/conv_kernel.h new file mode 100644 index 0000000..fb10394 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/conv_kernel.h @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +#include +#include +#include +#include +// clang-format on + +#include "cutlass_epilogue.h" +#include "cutlass_kernel.h" +#include "../common_cu.h" +#include "../cutlass_helper_implicit_gemm.h" +#include "../def_cutlass.h" + +template +at::Tensor conv_bias_generic_cutlass(at::Tensor& out_buf, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& bias, const int stride) +{ + using EpilogueOp = + LinearCombination<0, false, false, false, cutlass::half_t, cutlass::half_t, cutlass::half_t, + 128 / cutlass::sizeof_bits_v>; + + using Conv2dFpropKernel = typename CustomDefaultConv2dFpropWithBroadcast< + cutlass::half_t, cutlass::layout::TensorNHWC, cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, cutlass::half_t, cutlass::arch::OpClassTensorOp, + typename Sm::SmArch, typename Sm::ShapeThreadBlock, typename Sm::ShapeWarp, typename Sm::ShapeOp, + EpilogueOp, cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<8>, Sm::Stages, + cutlass::arch::OpMultiplyAdd, cutlass::conv::IteratorAlgorithm::kOptimized>::Kernel; + + using ImplicitGemm = CustomImplicitGemmConvolution; + + const int B = feature.size(0); + const int Cin = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int Cout = weight.size(0); + const int Cin_ = weight.size(1); + const int kernel = weight.size(2); + const int kernel_ = weight.size(3); + assert(Cin == Cin_ && kernel == kernel_); + const int pad = (kernel - 1) / 2; + + cutlass::conv::Conv2dProblemSize problem_size({ B, H, W, Cin }, // input + { Cout, kernel, kernel, Cin }, // kernel + { pad, pad, pad, pad }, // pad + { stride, stride }, // stride + { 1, 1 }, // dilation + { B, H / stride, W / stride, Cout }, // out + cutlass::conv::Mode::kCrossCorrelation, + 1 // split_k_slices + ); + + cutlass::TensorRef d_feature( + static_cast(feature.data_ptr()), + cutlass::make_Coord(feature.stride(3), feature.stride(2), feature.stride(0))); + cutlass::TensorRef d_weight( + static_cast(weight.data_ptr()), + cutlass::make_Coord(weight.stride(3), weight.stride(2), weight.stride(0))); + cutlass::TensorRef d_out( + static_cast(out_buf.data_ptr()), + cutlass::make_Coord(out_buf.stride(3), out_buf.stride(2), out_buf.stride(0))); + + typename ImplicitGemm::Arguments args(problem_size, d_feature, d_weight, d_out, d_out, {}, + cutlass::conv::SplitKMode::kSerial, bias.data_ptr(), + nullptr, 0, 0); + + ImplicitGemm implicit_gemm_op; + cutlass::Status status = implicit_gemm_op.can_implement(args); + if (status != cutlass::Status::kSuccess) { + std::cerr << "Failed to configure convolution operation." << std::endl; + return at::Tensor(); + } + + auto stream = at::cuda::getCurrentCUDAStream(); + status = implicit_gemm_op(args, nullptr, stream); + if (status != cutlass::Status::kSuccess) { + std::cerr << "Failed to run convolution operation." << std::endl; + return at::Tensor(); + } + + return out_buf; +} diff --git a/src/layers/extensions/inference/cutlass/cutlass_epilogue.h b/src/layers/extensions/inference/cutlass/cutlass_epilogue.h new file mode 100644 index 0000000..d24ef8e --- /dev/null +++ b/src/layers/extensions/inference/cutlass/cutlass_epilogue.h @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include +#include + +#include "../common_cu.h" +#include "../def_cutlass.h" + +template +__forceinline__ __device__ cutlass::Array +chunk_add(const cutlass::Array& intermediate) +{ + cutlass::Array y; + cutlass::Array z; + + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < N / 4; ++i) { + y[i] = static_cast(intermediate[i * 4 + 0] + intermediate[i * 4 + 1] + + intermediate[i * 4 + 2] + intermediate[i * 4 + 3]); + } + + memcpy(z.data(), y.data(), sizeof(y)); + + return z; +} + +// 0 or 1 additional input. If WithQuant, the addtional input is quant, otherwise, it is shortcut. +template +class LinearCombination { +public: + static bool const kIsSingleSource = true; + + using ElementOutput = ElementC_; + using ElementC = ElementC_; + using ElementAccumulator = ElementAccumulator_; + using ElementCompute = ElementCompute_; + using ElementVector = ElementC_; + static int const kElementsPerAccess = ElementsPerAccess; + static int const kCount = kElementsPerAccess; + + using FragmentAccumulator = cutlass::Array; + using FragmentCompute = cutlass::Array; + using FragmentC = cutlass::Array; + using FragmentOutput = cutlass::Array; + + using ElementZ = ElementC_; + using ElementT = cutlass::int4b_t; + using FragmentZ = cutlass::Array; + using FragmentT = cutlass::Array; + + static bool const kIsHeavy = WSiLU; + static bool const kStoreZ = !ChunkAdd; + static bool const kStoreT = ChunkAdd; + + /// Host-constructable parameters structure + struct Params { + + CUTLASS_HOST_DEVICE + Params() {} + }; + +public: + /// Constructor from Params + CUTLASS_HOST_DEVICE + LinearCombination(Params const&) {} + + /// The "source" tensor corresponds to the residual input + CUTLASS_HOST_DEVICE + bool is_source_needed() const { return NumAdditonalInputs > 0; } + + CUTLASS_HOST_DEVICE + void operator()(FragmentZ& frag_Z, FragmentT& frag_T, FragmentAccumulator const& AB, + FragmentC const& residual, FragmentCompute const& bias) const + { + FragmentCompute tmp_Accum = + cutlass::NumericArrayConverter()(AB); + FragmentCompute tmp_residual = + cutlass::NumericArrayConverter()(residual); + + cutlass::plus plus_op; + FragmentCompute intermediate = plus_op(tmp_Accum, bias); + + if constexpr (WSiLU) { + WSiLUOp wsilu_op; + intermediate = wsilu_op(intermediate); + } + + if constexpr (WithQuant) { + cutlass::multiplies multiply_op; + intermediate = multiply_op(intermediate, tmp_residual); + } else { + intermediate = plus_op(intermediate, tmp_residual); + } + + if constexpr (ChunkAdd) { + frag_T = chunk_add(intermediate); + } else { + cutlass::NumericArrayConverter convert_z; + frag_Z = convert_z(intermediate); + } + } + + CUTLASS_HOST_DEVICE + void operator()(FragmentZ& frag_Z, FragmentT& frag_T, FragmentAccumulator const& AB, + FragmentCompute const& bias) const + { + FragmentCompute tmp_Accum = + cutlass::NumericArrayConverter()(AB); + + cutlass::plus plus_op; + FragmentCompute intermediate = plus_op(tmp_Accum, bias); + + if constexpr (WSiLU) { + WSiLUOp wsilu_op; + intermediate = wsilu_op(intermediate); + } + + if constexpr (ChunkAdd) { + frag_T = chunk_add(intermediate); + } else { + cutlass::NumericArrayConverter convert_z; + frag_Z = convert_z(intermediate); + } + } + + /// Functionally required for serial reduction in the epilogue + /// IMPORTANT: Split-k is supported only when ActivationOp is Identity. + CUTLASS_HOST_DEVICE + void set_k_partition(int, int) {} +}; + +// 2 additional inputs. +// If WithQuant, the second addtional input is quant, otherwise, it is shortcut. +// The first additonal input is always shortcut. +template +class LinearCombination<2, WSiLU, WithQuant, ChunkAdd, ElementC_, ElementAccumulator_, + ElementCompute_, ElementsPerAccess> { +public: + static bool const kIsSingleSource = false; + + using ElementOutput = ElementC_; + using ElementC = ElementC_; + using ElementAccumulator = ElementAccumulator_; + using ElementCompute = ElementCompute_; + using ElementVector = ElementC_; + static int const kElementsPerAccess = ElementsPerAccess; + static int const kCount = kElementsPerAccess; + + using FragmentAccumulator = cutlass::Array; + using FragmentCompute = cutlass::Array; + using FragmentC = cutlass::Array; + using FragmentOutput = cutlass::Array; + + using ElementZ = ElementC_; + using ElementT = cutlass::int4b_t; + using FragmentZ = cutlass::Array; + using FragmentT = cutlass::Array; + + static bool const kIsHeavy = WSiLU; + static bool const kStoreZ = !ChunkAdd; + static bool const kStoreT = ChunkAdd; + + /// Host-constructable parameters structure + struct Params { + + CUTLASS_HOST_DEVICE + Params() {} + }; + +public: + /// Constructor from Params + CUTLASS_HOST_DEVICE + LinearCombination(Params const&) {} + + /// The "source" tensor corresponds to the residual input + CUTLASS_HOST_DEVICE + bool is_source_needed() const { return true; } + + CUTLASS_HOST_DEVICE + void operator()(FragmentZ& frag_Z, FragmentT& frag_T, FragmentAccumulator const& AB, + FragmentC const& residual1, FragmentC const& residual2, + FragmentCompute const& bias) const + { + FragmentCompute tmp_Accum = + cutlass::NumericArrayConverter()(AB); + FragmentCompute tmp_residual1 = + cutlass::NumericArrayConverter()(residual1); + FragmentCompute tmp_residual2 = + cutlass::NumericArrayConverter()(residual2); + + cutlass::plus plus_op; + FragmentCompute intermediate = plus_op(tmp_Accum, bias); + + if constexpr (WSiLU) { + WSiLUOp wsilu_op; + intermediate = wsilu_op(intermediate); + } + + intermediate = plus_op(intermediate, tmp_residual1); + + if constexpr (WithQuant) { + cutlass::multiplies multiply_op; + intermediate = multiply_op(intermediate, tmp_residual2); + } else { + intermediate = plus_op(intermediate, tmp_residual2); + } + + if constexpr (ChunkAdd) { + frag_T = chunk_add(intermediate); + } else { + cutlass::NumericArrayConverter convert_z; + frag_Z = convert_z(intermediate); + } + } + + /// Should never be called + CUTLASS_HOST_DEVICE + void operator()(FragmentZ&, FragmentT&, FragmentAccumulator const&, FragmentCompute const&) const + { + } + + /// Functionally required for serial reduction in the epilogue + /// IMPORTANT: Split-k is supported only when ActivationOp is Identity. + CUTLASS_HOST_DEVICE + void set_k_partition(int, int) {} +}; diff --git a/src/layers/extensions/inference/cutlass/cutlass_helper_d3x3.h b/src/layers/extensions/inference/cutlass/cutlass_helper_d3x3.h new file mode 100644 index 0000000..f49e794 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/cutlass_helper_d3x3.h @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +#include +// clang-format on + +/** + * These 3 classes/structs are rewritten: + * 1. cutlass::conv::kernel::DirectConvolution -> CustomDirectConvolutionKernel + * 2. cutlass::conv::kernel::DefaultDepthwiseDirect2dConvFprop -> CustomDefaultDepthwiseDirect2dConvFprop + * 3. cutlass::conv::device::DirectConvolution -> CustomDirectConvolutionDevice + */ + +/// Original file: cutlass/conv/kernel/direct_convolution.h +/// to add PDL sync points +template +struct CustomDirectConvolutionKernel { + using Base = + cutlass::conv::kernel::DirectConvolution; + using ElementA = typename Base::ElementA; + using LayoutA = typename Base::LayoutA; + using ElementB = typename Base::ElementB; + using LayoutB = typename Base::LayoutB; + using ElementC = typename Base::ElementC; + using LayoutC = typename Base::LayoutC; + using ElementAccumulator = typename Base::ElementAccumulator; + using ElementCompute = typename Base::ElementCompute; + using OperatorClass = typename Base::OperatorClass; + using ArchTag = typename Base::ArchTag; + using ThreadblockShape = typename Base::ThreadblockShape; + using WarpShape = typename Base::WarpShape; + using InstructionShape = typename Base::InstructionShape; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + using EpilogueOutputOp = typename Base::EpilogueOutputOp; + static int const kStages = Base::kStages; + static int const kConvDim = Base::kConvDim; + using WarpMmaOperator = typename Base::WarpMmaOperator; + using ArchMmaOperator = typename Base::ArchMmaOperator; + using MathOperator = typename Base::MathOperator; + + static cutlass::conv::Operator const kConvolutionalOperator = Base::kConvolutionalOperator; + static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Base::kIteratorAlgorithm; + static cutlass::conv::StrideSupport const kStrideSupport = Base::kStrideSupport; + static cutlass::conv::GroupMode const kGroupMode = Base::kGroupMode; + + using Arguments = typename Base::Arguments; + using ReorderKernel = typename Base::ReorderKernel; + using Mma = typename Base::Mma; + using Epilogue = typename Base::Epilogue; + using Params = typename Base::Params; + using SharedStorage = typename Base::SharedStorage; + + using TensorRefC = cutlass::TensorRef; + using ConvProblemSize = ConvProblemSize_; + using ConvOutputIteratorParameter = cutlass::epilogue::threadblock::ConvOutputIteratorParameter< + LayoutC, typename Epilogue::OutputTileIterator::Layout, TensorRefC, ConvOperator, ConvProblemSize>; + + /// Executes one ImplicitGEMM + /// The aim is to add PDL sync point to this function. + CUTLASS_DEVICE + void operator()(Params const& params, SharedStorage& shared_storage) + { + // Compute threadblock location + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord threadblock_tile_idx = + threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // Early exit if threadblock is out of range + if (params.grid_tiled_shape.m() <= threadblock_tile_idx.m() + || params.grid_tiled_shape.n() <= threadblock_tile_idx.n()) { + cudaGDC(); + return; + } + + // Compute position within threadblock + int thread_idx = threadIdx.x; + int iterator_column_offset = 0; + int filter_row_offset = 0; + if (kGroupMode != cutlass::conv::GroupMode::kNone) { + if (kGroupMode == cutlass::conv::GroupMode::kDepthwise) { + iterator_column_offset += threadblock_tile_idx.n() * Mma::Shape::kN; + } + } + + // Construct iterators to A and B operands + typename Mma::IteratorA iterator_A( + params.iterator_A, params.problem_size, params.ptr_A, thread_idx, + cutlass::MatrixCoord(threadblock_tile_idx.m() + threadblock_tile_idx.k(), + iterator_column_offset)); + + typename Mma::IteratorB iterator_B( + params.iterator_B, params.problem_size, params.ptr_reordered_B, thread_idx, + cutlass::MatrixCoord(filter_row_offset, iterator_column_offset)); + + // Broadcast the warp_id computed by lane 0 to ensure dependent code + // is compiled as warp-uniform. + int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + int lane_idx = threadIdx.x % 32; + + // + // Main loop + // + + // Construct thread-scoped matrix multiply + Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx); + + typename Mma::FragmentC accumulators; + + accumulators.clear(); + + // + // Epilogue + // + + EpilogueOutputOp output_op(params.output_op); + + // Compute logical position within grid + threadblock_tile_idx = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + cutlass::MatrixCoord threadblock_offset(threadblock_tile_idx.m() + threadblock_tile_idx.k(), + threadblock_tile_idx.n() * Mma::Shape::kN); + + // Tile iterator writing to destination tensor + typename Epilogue::OutputTileIterator iterator_D( + params.iterator_D, params.ptr_D, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, threadblock_offset); + + // Tile iterator reading from source accumulator tensor + typename Epilogue::OutputTileIterator iterator_C( + params.iterator_C, params.ptr_C, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, threadblock_offset); + + // Construct the epilogue + Epilogue epilogue(shared_storage.epilogue, thread_idx, warp_idx, lane_idx); + + // Compute threadblock-scoped matrix multiply-add + // Epilogue is fused in the mainloop + cudaGDC(); + mma(params.gemm_k_iterations, accumulators, iterator_A, params.iterator_A, iterator_B, + params.iterator_B, accumulators, epilogue, output_op, iterator_D, iterator_C, + params.split_k_slices); + } +}; + +/// Original file: cutlass/conv/kernel/default_depthwise_fprop.h +/// to invoke CustomDirectConvolutionKernel +template , + int AlignmentB = 128 / cutlass::sizeof_bits_v> +struct CustomDefaultDepthwiseDirect2dConvFprop { + using Base = cutlass::conv::kernel::DefaultDepthwiseDirect2dConvFprop< + ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC, ElementAccumulator, OperatorClass, + ArchTag, ThreadblockShape, ThreadBlockOutputShape, FilterShape, WarpShape, InstructionShape, + EpilogueOutputOp, ThreadblockSwizzle, Stages, MathOperatorTag, IteratorAlgorithm, + StrideSupport, StrideShape, DilationShape, AlignmentA, AlignmentB>; + using Kernel = + CustomDirectConvolutionKernel; +}; + +/// Original file: cutlass/conv/device/direct_convolution.h +/// to remove the launch of the ReorderKernel +/// to add "cudaLaunchKernelEx" to run() +template +class CustomDirectConvolutionDevice { +public: + using Base = cutlass::conv::device::DirectConvolution; + using UnderlyingKernel = typename Base::UnderlyingKernel; + using ThreadblockShape = typename Base::ThreadblockShape; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + using Arguments = typename Base::Arguments; + + static cutlass::conv::Operator const kConvolutionalOperator = Base::kConvolutionalOperator; + static cutlass::conv::GroupMode const kGroupMode = Base::kGroupMode; + static int const kWarpCount = Base::kWarpCount; + +private: + typename UnderlyingKernel::Params params_; + +public: + static cutlass::Status can_implement(Arguments const& args) + { + return Base::can_implement(args); + } + + cutlass::Status initialize(Arguments const& args, void* workspace = nullptr, + cudaStream_t stream = nullptr) + { + params_ = typename UnderlyingKernel::Params(args, static_cast(workspace)); + int smem_size = int(sizeof(typename UnderlyingKernel::SharedStorage)); + if (smem_size >= (48 << 10)) { + cudaError_t result = + cudaFuncSetAttribute(cutlass::Kernel, + cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size); + if (result != cudaSuccess) { + return cutlass::Status::kErrorInternal; + } + } + return cutlass::Status::kSuccess; + } + + cutlass::Status operator()(Arguments const& args, void* workspace = nullptr, + cudaStream_t stream = nullptr) + { + cutlass::Status status = initialize(args, workspace, stream); + if (status == cutlass::Status::kSuccess) { + status = run(stream); + } + return status; + } + + // Only this function is modified. To remove the launch of ReorderKernel. + cutlass::Status run(cudaStream_t stream = nullptr) + { + // Launch main kernel + ThreadblockSwizzle threadblock_swizzle; + + dim3 grid = threadblock_swizzle.get_grid_shape(params_.grid_tiled_shape); + dim3 block(32 * kWarpCount, 1, 1); + + // Dynamic SMEM size based on input params. + int smem_size = int(params_.get_smem_size()); + + // Make sure we can use that much shared memory. + cudaError_t status = + cudaFuncSetAttribute(cutlass::Kernel, + cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size); + if (status != cudaSuccess) { + return cutlass::Status::kErrorInternal; + } + + cutlass::arch::synclog_setup(); + + cudaLaunchConfig_t config; + config.gridDim = grid; + config.blockDim = block; + config.dynamicSmemBytes = smem_size; + config.stream = stream; + auto attr = get_cuda_launch_attribute(); + config.attrs = &attr; + config.numAttrs = 1; + + cudaLaunchKernelEx(&config, &cutlass::Kernel, params_); + + cudaError_t result = cudaGetLastError(); + + return result == cudaSuccess ? cutlass::Status::kSuccess : cutlass::Status::kErrorInternal; + } +}; diff --git a/src/layers/extensions/inference/cutlass/cutlass_kernel.h b/src/layers/extensions/inference/cutlass/cutlass_kernel.h new file mode 100644 index 0000000..333b6e9 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/cutlass_kernel.h @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "../common_cu.h" + +struct Sm75 { + using SmArch = cutlass::arch::Sm75; + using ShapeThreadBlock = cutlass::gemm::GemmShape<128, 128, 32>; + using ShapeWarp = cutlass::gemm::GemmShape<64, 64, 32>; + using ShapeOp = cutlass::gemm::GemmShape<16, 8, 8>; + static constexpr int Stages = 2; +}; + +template +__forceinline__ auto launch_cutlass_switcher(const int sm, Func func, const int hint) +{ + assert(sm >= 80); + if constexpr (!Cutlass2Only) { + switch (hint) { +#if CURRENT_DEVICE_SM == 90 + case 30: + return func(Hint30{}); + case 31: + return func(Hint31{}); + case 32: + return func(Hint32{}); + case 33: + return func(Hint33{}); + case 34: + return func(Hint34{}); + case 35: + return func(Hint35{}); + case 36: + return func(Hint36{}); + case 37: + return func(Hint37{}); +#elif CURRENT_DEVICE_SM == 100 + case 38: + return func(Hint38{}); + case 39: + return func(Hint39{}); + case 40: + return func(Hint40{}); + case 41: + return func(Hint41{}); + case 42: + return func(Hint42{}); + case 43: + return func(Hint43{}); + case 44: + return func(Hint44{}); + case 45: + return func(Hint45{}); + case 46: + return func(Hint46{}); + case 47: + return func(Hint47{}); + case 48: + return func(Hint48{}); + case 49: + return func(Hint49{}); + case 50: + return func(Hint50{}); + case 51: + return func(Hint51{}); + case 52: + return func(Hint52{}); + case 53: + return func(Hint53{}); + case 54: + return func(Hint54{}); + case 55: + return func(Hint55{}); + case 56: + return func(Hint56{}); + case 57: + return func(Hint57{}); + case 58: + return func(Hint58{}); + case 59: + return func(Hint59{}); + case 60: + return func(Hint60{}); + case 61: + return func(Hint61{}); + case 62: + return func(Hint62{}); + case 63: + return func(Hint63{}); + case 64: + return func(Hint64{}); + case 65: + return func(Hint65{}); + case 66: + return func(Hint66{}); + case 67: + return func(Hint67{}); + case 68: + return func(Hint68{}); + case 69: + return func(Hint69{}); + case 70: + return func(Hint70{}); + case 71: + return func(Hint71{}); + case 72: + return func(Hint72{}); + case 73: + return func(Hint73{}); + case 74: + return func(Hint74{}); + case 75: + return func(Hint75{}); + case 76: + return func(Hint76{}); + case 77: + return func(Hint77{}); + case 78: + return func(Hint78{}); + case 79: + return func(Hint79{}); + case 80: + return func(Hint80{}); + case 81: + return func(Hint81{}); + case 82: + return func(Hint82{}); + case 83: + return func(Hint83{}); + case 84: + return func(Hint84{}); + case 85: + return func(Hint85{}); + case 86: + return func(Hint86{}); + case 87: + return func(Hint87{}); + case 88: + return func(Hint88{}); + case 89: + return func(Hint89{}); + case 90: + return func(Hint90{}); + case 91: + return func(Hint91{}); + case 92: + return func(Hint92{}); + case 93: + return func(Hint93{}); + case 94: + return func(Hint94{}); + case 95: + return func(Hint95{}); +#endif + } + } + switch (hint) { +#if CURRENT_DEVICE_SM >= 80 + case 0: + return func(Hint0{}); + case 1: + return func(Hint1{}); + case 2: + return func(Hint2{}); + case 3: + return func(Hint3{}); + case 4: + return func(Hint4{}); + case 5: + return func(Hint5{}); + case 6: + return func(Hint6{}); + case 7: + return func(Hint7{}); + case 8: + return func(Hint8{}); + case 9: + return func(Hint9{}); + case 10: + return func(Hint10{}); + case 11: + return func(Hint11{}); + case 12: + return func(Hint12{}); + case 13: + return func(Hint13{}); + case 14: + return func(Hint14{}); + case 15: + return func(Hint15{}); + case 16: + return func(Hint16{}); + case 17: + return func(Hint17{}); + case 18: + return func(Hint18{}); + case 19: + return func(Hint19{}); + case 20: + return func(Hint20{}); + case 21: + return func(Hint21{}); + case 22: + return func(Hint22{}); + case 23: + return func(Hint23{}); + case 24: + return func(Hint24{}); + case 25: + return func(Hint25{}); + case 26: + return func(Hint26{}); + case 27: + return func(Hint27{}); + case 28: + return func(Hint28{}); + case 29: + return func(Hint29{}); +#endif + default: + using Type = decltype(func(Hint0{})); + static_assert(std::is_same_v); + return at::Tensor(); + } +} + +template +__forceinline__ auto +launch_cutlass_helper(const int sm, Func func, std::unordered_map& map, + const std::string& map_name, const int C2, const int C1, const int H, + const int W, const int kernel = 0, const int stride = 0) +{ + if (sm == 75) { + return func(Sm75{}); + } + const uint64_t key = conv_key(sm, W, H, C2, C1, stride, kernel); + int best_hint = -1; + auto it = map.find(key); + if (it == map.end()) { + return launch_cutlass_switcher(sm, func, 14); + } else { + best_hint = it->second; + } + return launch_cutlass_switcher(sm, func, best_hint); +} diff --git a/src/layers/extensions/inference/cutlass/d3x3.cu b/src/layers/extensions/inference/cutlass/d3x3.cu new file mode 100644 index 0000000..19c5f99 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/d3x3.cu @@ -0,0 +1,446 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "d3x3_kernel.h" + +const std::string HINT_MAP_D3x3_NAME = "HINT_MAP_D3x3"; +std::unordered_map HINT_MAP_D3x3 = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 0, 1280, 192, 32, 0, 0), 5 }, + { conv_key(80, 0, 1920, 272, 32, 0, 0), 0 }, + { conv_key(80, 0, 2560, 384, 32, 0, 0), 5 }, + { conv_key(80, 0, 2560, 384, 64, 0, 0), 5 }, + { conv_key(80, 0, 3840, 544, 32, 0, 0), 5 }, + { conv_key(80, 0, 3840, 544, 64, 0, 0), 15 }, + { conv_key(80, 0, 5120, 720, 128, 0, 0), 65555 }, + { conv_key(80, 0, 5120, 720, 192, 0, 0), 65547 }, + { conv_key(80, 0, 5120, 768, 32, 0, 0), 15 }, + { conv_key(80, 0, 5120, 768, 64, 0, 0), 65620 }, + { conv_key(80, 0, 5120, 768, 128, 0, 0), 65556 }, + { conv_key(80, 0, 7680, 1088, 32, 0, 0), 17 }, + { conv_key(80, 0, 7680, 1088, 64, 0, 0), 65574 }, + { conv_key(80, 0, 7680, 1088, 128, 0, 0), 65624 }, + { conv_key(80, 0, 7680, 1088, 192, 0, 0), 65624 }, + { conv_key(80, 0, 10240, 1440, 48, 0, 0), 65604 }, + { conv_key(80, 0, 10240, 1440, 64, 0, 0), 65576 }, + { conv_key(80, 0, 10240, 1440, 96, 0, 0), 65562 }, + { conv_key(80, 0, 10240, 1440, 128, 0, 0), 65560 }, + { conv_key(80, 0, 15360, 2160, 128, 0, 0), 65624 }, + { conv_key(80, 0, 15360, 2160, 192, 0, 0), 65619 }, + { conv_key(80, 0, 15360, 2176, 32, 0, 0), 65663 }, + { conv_key(80, 0, 15360, 2176, 48, 0, 0), 65662 }, + { conv_key(80, 0, 15360, 2176, 64, 0, 0), 65650 }, + { conv_key(80, 0, 15360, 2176, 96, 0, 0), 65636 }, + { conv_key(80, 0, 15360, 2176, 128, 0, 0), 65624 }, + { conv_key(80, 0, 30720, 4320, 48, 0, 0), 65646 }, + { conv_key(80, 0, 30720, 4320, 64, 0, 0), 65637 }, + { conv_key(80, 0, 30720, 4320, 96, 0, 0), 65628 }, + { conv_key(80, 0, 30720, 4320, 128, 0, 0), 65623 }, + { conv_key(80, 7, 4, 64, 64, 0, 0), 5 }, + { conv_key(80, 7, 4, 128, 128, 0, 0), 0 }, + { conv_key(80, 13, 8, 64, 64, 0, 0), 0 }, + { conv_key(80, 13, 8, 128, 128, 0, 0), 0 }, + { conv_key(80, 14, 8, 64, 64, 0, 0), 0 }, + { conv_key(80, 14, 8, 128, 128, 0, 0), 5 }, + { conv_key(80, 14, 8, 256, 256, 0, 0), 0 }, + { conv_key(80, 20, 12, 64, 64, 0, 0), 0 }, + { conv_key(80, 20, 12, 128, 128, 0, 0), 0 }, + { conv_key(80, 26, 15, 128, 128, 0, 0), 0 }, + { conv_key(80, 26, 15, 192, 192, 0, 0), 5 }, + { conv_key(80, 26, 15, 512, 512, 0, 0), 0 }, + { conv_key(80, 26, 15, 768, 768, 0, 0), 5 }, + { conv_key(80, 26, 16, 64, 64, 0, 0), 0 }, + { conv_key(80, 26, 16, 128, 128, 0, 0), 0 }, + { conv_key(80, 26, 16, 256, 256, 0, 0), 5 }, + { conv_key(80, 28, 16, 64, 64, 0, 0), 0 }, + { conv_key(80, 28, 16, 128, 128, 0, 0), 0 }, + { conv_key(80, 28, 16, 256, 256, 0, 0), 5 }, + { conv_key(80, 28, 16, 512, 512, 0, 0), 5 }, + { conv_key(80, 30, 17, 64, 64, 0, 0), 0 }, + { conv_key(80, 30, 17, 128, 128, 0, 0), 0 }, + { conv_key(80, 40, 24, 64, 64, 0, 0), 0 }, + { conv_key(80, 40, 24, 128, 128, 0, 0), 5 }, + { conv_key(80, 40, 24, 256, 256, 0, 0), 5 }, + { conv_key(80, 52, 30, 128, 128, 0, 0), 0 }, + { conv_key(80, 52, 30, 192, 192, 0, 0), 5 }, + { conv_key(80, 52, 30, 256, 256, 0, 0), 2 }, + { conv_key(80, 52, 30, 384, 384, 0, 0), 2 }, + { conv_key(80, 52, 30, 512, 512, 0, 0), 15 }, + { conv_key(80, 52, 30, 768, 768, 0, 0), 65550 }, + { conv_key(80, 52, 32, 64, 64, 0, 0), 0 }, + { conv_key(80, 52, 32, 128, 128, 0, 0), 0 }, + { conv_key(80, 52, 32, 256, 256, 0, 0), 2 }, + { conv_key(80, 52, 32, 512, 512, 0, 0), 2 }, + { conv_key(80, 60, 34, 64, 64, 0, 0), 5 }, + { conv_key(80, 60, 34, 128, 128, 0, 0), 5 }, + { conv_key(80, 60, 34, 256, 256, 0, 0), 15 }, + { conv_key(80, 80, 45, 128, 128, 0, 0), 15 }, + { conv_key(80, 80, 45, 192, 192, 0, 0), 6 }, + { conv_key(80, 80, 45, 512, 512, 0, 0), 65549 }, + { conv_key(80, 80, 45, 768, 768, 0, 0), 65547 }, + { conv_key(80, 80, 48, 64, 64, 0, 0), 5 }, + { conv_key(80, 80, 48, 128, 128, 0, 0), 15 }, + { conv_key(80, 80, 48, 256, 256, 0, 0), 65558 }, + { conv_key(80, 80, 48, 512, 512, 0, 0), 65555 }, + { conv_key(80, 104, 60, 128, 128, 0, 0), 15 }, + { conv_key(80, 104, 60, 192, 192, 0, 0), 65551 }, + { conv_key(80, 104, 60, 256, 256, 0, 0), 65588 }, + { conv_key(80, 104, 60, 384, 384, 0, 0), 65562 }, + { conv_key(80, 104, 60, 512, 512, 0, 0), 65554 }, + { conv_key(80, 120, 68, 64, 64, 0, 0), 15 }, + { conv_key(80, 120, 68, 128, 128, 0, 0), 65602 }, + { conv_key(80, 120, 68, 192, 192, 0, 0), 65646 }, + { conv_key(80, 120, 68, 256, 256, 0, 0), 65572 }, + { conv_key(80, 120, 68, 512, 512, 0, 0), 65624 }, + { conv_key(80, 120, 68, 768, 768, 0, 0), 65624 }, + { conv_key(80, 160, 90, 128, 128, 0, 0), 65596 }, + { conv_key(80, 160, 90, 192, 192, 0, 0), 65600 }, + { conv_key(80, 160, 90, 256, 256, 0, 0), 65576 }, + { conv_key(80, 160, 90, 384, 384, 0, 0), 65628 }, + { conv_key(80, 160, 90, 512, 512, 0, 0), 65623 }, + { conv_key(80, 240, 135, 128, 128, 0, 0), 65663 }, + { conv_key(80, 240, 135, 192, 192, 0, 0), 65664 }, + { conv_key(80, 240, 135, 512, 512, 0, 0), 65624 }, + { conv_key(80, 240, 135, 768, 768, 0, 0), 65619 }, + { conv_key(80, 240, 136, 64, 64, 0, 0), 65662 }, + { conv_key(80, 240, 136, 128, 128, 0, 0), 65663 }, + { conv_key(80, 240, 136, 192, 192, 0, 0), 65663 }, + { conv_key(80, 240, 136, 256, 256, 0, 0), 65647 }, + { conv_key(80, 240, 136, 384, 384, 0, 0), 65636 }, + { conv_key(80, 240, 136, 512, 512, 0, 0), 65624 }, + { conv_key(80, 480, 270, 128, 128, 0, 0), 65662 }, + { conv_key(80, 480, 270, 192, 192, 0, 0), 65646 }, + { conv_key(80, 480, 270, 256, 256, 0, 0), 65637 }, + { conv_key(80, 480, 270, 384, 384, 0, 0), 65627 }, + { conv_key(80, 480, 270, 512, 512, 0, 0), 65623 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 0, 1280, 192, 32, 0, 0), 2 }, + { conv_key(89, 0, 1920, 272, 32, 0, 0), 10 }, + { conv_key(89, 0, 2560, 384, 32, 0, 0), 8 }, + { conv_key(89, 0, 2560, 384, 64, 0, 0), 6 }, + { conv_key(89, 0, 3840, 544, 32, 0, 0), 6 }, + { conv_key(89, 0, 3840, 544, 64, 0, 0), 6 }, + { conv_key(89, 0, 5120, 720, 128, 0, 0), 65551 }, + { conv_key(89, 0, 5120, 720, 192, 0, 0), 65621 }, + { conv_key(89, 0, 5120, 768, 32, 0, 0), 15 }, + { conv_key(89, 0, 5120, 768, 64, 0, 0), 65571 }, + { conv_key(89, 0, 5120, 768, 128, 0, 0), 65551 }, + { conv_key(89, 0, 7680, 1088, 32, 0, 0), 65637 }, + { conv_key(89, 0, 7680, 1088, 64, 0, 0), 65624 }, + { conv_key(89, 0, 7680, 1088, 128, 0, 0), 65618 }, + { conv_key(89, 0, 7680, 1088, 192, 0, 0), 65549 }, + { conv_key(89, 0, 10240, 1440, 48, 0, 0), 65631 }, + { conv_key(89, 0, 10240, 1440, 64, 0, 0), 65626 }, + { conv_key(89, 0, 10240, 1440, 96, 0, 0), 65621 }, + { conv_key(89, 0, 10240, 1440, 128, 0, 0), 65618 }, + { conv_key(89, 0, 15360, 2160, 128, 0, 0), 65559 }, + { conv_key(89, 0, 15360, 2160, 192, 0, 0), 65662 }, + { conv_key(89, 0, 15360, 2176, 32, 0, 0), 65639 }, + { conv_key(89, 0, 15360, 2176, 48, 0, 0), 65631 }, + { conv_key(89, 0, 15360, 2176, 64, 0, 0), 65625 }, + { conv_key(89, 0, 15360, 2176, 96, 0, 0), 65620 }, + { conv_key(89, 0, 15360, 2176, 128, 0, 0), 65618 }, + { conv_key(89, 0, 30720, 4320, 48, 0, 0), 65653 }, + { conv_key(89, 0, 30720, 4320, 64, 0, 0), 65548 }, + { conv_key(89, 0, 30720, 4320, 96, 0, 0), 65544 }, + { conv_key(89, 0, 30720, 4320, 128, 0, 0), 65542 }, + { conv_key(89, 7, 4, 64, 64, 0, 0), 7 }, + { conv_key(89, 7, 4, 128, 128, 0, 0), 11 }, + { conv_key(89, 13, 8, 64, 64, 0, 0), 6 }, + { conv_key(89, 13, 8, 128, 128, 0, 0), 16 }, + { conv_key(89, 14, 8, 64, 64, 0, 0), 11 }, + { conv_key(89, 14, 8, 128, 128, 0, 0), 11 }, + { conv_key(89, 14, 8, 256, 256, 0, 0), 15 }, + { conv_key(89, 20, 12, 64, 64, 0, 0), 6 }, + { conv_key(89, 20, 12, 128, 128, 0, 0), 15 }, + { conv_key(89, 26, 15, 128, 128, 0, 0), 10 }, + { conv_key(89, 26, 15, 192, 192, 0, 0), 12 }, + { conv_key(89, 26, 15, 512, 512, 0, 0), 6 }, + { conv_key(89, 26, 15, 768, 768, 0, 0), 10 }, + { conv_key(89, 26, 16, 64, 64, 0, 0), 16 }, + { conv_key(89, 26, 16, 128, 128, 0, 0), 11 }, + { conv_key(89, 26, 16, 256, 256, 0, 0), 4 }, + { conv_key(89, 28, 16, 64, 64, 0, 0), 15 }, + { conv_key(89, 28, 16, 128, 128, 0, 0), 7 }, + { conv_key(89, 28, 16, 256, 256, 0, 0), 6 }, + { conv_key(89, 28, 16, 512, 512, 0, 0), 7 }, + { conv_key(89, 30, 17, 64, 64, 0, 0), 6 }, + { conv_key(89, 30, 17, 128, 128, 0, 0), 11 }, + { conv_key(89, 40, 24, 64, 64, 0, 0), 20 }, + { conv_key(89, 40, 24, 128, 128, 0, 0), 11 }, + { conv_key(89, 40, 24, 256, 256, 0, 0), 20 }, + { conv_key(89, 52, 30, 128, 128, 0, 0), 15 }, + { conv_key(89, 52, 30, 192, 192, 0, 0), 20 }, + { conv_key(89, 52, 30, 256, 256, 0, 0), 10 }, + { conv_key(89, 52, 30, 384, 384, 0, 0), 15 }, + { conv_key(89, 52, 30, 512, 512, 0, 0), 65618 }, + { conv_key(89, 52, 30, 768, 768, 0, 0), 65545 }, + { conv_key(89, 52, 32, 64, 64, 0, 0), 4 }, + { conv_key(89, 52, 32, 128, 128, 0, 0), 15 }, + { conv_key(89, 52, 32, 256, 256, 0, 0), 10 }, + { conv_key(89, 52, 32, 512, 512, 0, 0), 65618 }, + { conv_key(89, 60, 34, 64, 64, 0, 0), 20 }, + { conv_key(89, 60, 34, 128, 128, 0, 0), 6 }, + { conv_key(89, 60, 34, 256, 256, 0, 0), 20 }, + { conv_key(89, 80, 45, 128, 128, 0, 0), 10 }, + { conv_key(89, 80, 45, 192, 192, 0, 0), 20 }, + { conv_key(89, 80, 45, 512, 512, 0, 0), 65551 }, + { conv_key(89, 80, 45, 768, 768, 0, 0), 65621 }, + { conv_key(89, 80, 48, 64, 64, 0, 0), 15 }, + { conv_key(89, 80, 48, 128, 128, 0, 0), 10 }, + { conv_key(89, 80, 48, 256, 256, 0, 0), 65641 }, + { conv_key(89, 80, 48, 512, 512, 0, 0), 65551 }, + { conv_key(89, 104, 60, 128, 128, 0, 0), 65565 }, + { conv_key(89, 104, 60, 192, 192, 0, 0), 65590 }, + { conv_key(89, 104, 60, 256, 256, 0, 0), 65641 }, + { conv_key(89, 104, 60, 384, 384, 0, 0), 65621 }, + { conv_key(89, 104, 60, 512, 512, 0, 0), 65618 }, + { conv_key(89, 120, 68, 64, 64, 0, 0), 10 }, + { conv_key(89, 120, 68, 128, 128, 0, 0), 65633 }, + { conv_key(89, 120, 68, 192, 192, 0, 0), 65570 }, + { conv_key(89, 120, 68, 256, 256, 0, 0), 65624 }, + { conv_key(89, 120, 68, 512, 512, 0, 0), 65618 }, + { conv_key(89, 120, 68, 768, 768, 0, 0), 65621 }, + { conv_key(89, 160, 90, 128, 128, 0, 0), 65596 }, + { conv_key(89, 160, 90, 192, 192, 0, 0), 65631 }, + { conv_key(89, 160, 90, 256, 256, 0, 0), 65626 }, + { conv_key(89, 160, 90, 384, 384, 0, 0), 65621 }, + { conv_key(89, 160, 90, 512, 512, 0, 0), 65618 }, + { conv_key(89, 240, 135, 128, 128, 0, 0), 65640 }, + { conv_key(89, 240, 135, 192, 192, 0, 0), 65631 }, + { conv_key(89, 240, 135, 512, 512, 0, 0), 65618 }, + { conv_key(89, 240, 135, 768, 768, 0, 0), 65630 }, + { conv_key(89, 240, 136, 64, 64, 0, 0), 65662 }, + { conv_key(89, 240, 136, 128, 128, 0, 0), 65639 }, + { conv_key(89, 240, 136, 192, 192, 0, 0), 65631 }, + { conv_key(89, 240, 136, 256, 256, 0, 0), 65625 }, + { conv_key(89, 240, 136, 384, 384, 0, 0), 65620 }, + { conv_key(89, 240, 136, 512, 512, 0, 0), 65559 }, + { conv_key(89, 480, 270, 128, 128, 0, 0), 65640 }, + { conv_key(89, 480, 270, 192, 192, 0, 0), 65597 }, + { conv_key(89, 480, 270, 256, 256, 0, 0), 65549 }, + { conv_key(89, 480, 270, 384, 384, 0, 0), 65544 }, + { conv_key(89, 480, 270, 512, 512, 0, 0), 65542 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 0, 1280, 192, 32, 0, 0), 10 }, + { conv_key(90, 0, 1920, 272, 32, 0, 0), 6 }, + { conv_key(90, 0, 2560, 384, 32, 0, 0), 0 }, + { conv_key(90, 0, 2560, 384, 64, 0, 0), 0 }, + { conv_key(90, 0, 3840, 544, 32, 0, 0), 0 }, + { conv_key(90, 0, 3840, 544, 64, 0, 0), 65631 }, + { conv_key(90, 0, 5120, 720, 128, 0, 0), 65618 }, + { conv_key(90, 0, 5120, 720, 192, 0, 0), 65621 }, + { conv_key(90, 0, 5120, 768, 32, 0, 0), 65646 }, + { conv_key(90, 0, 5120, 768, 64, 0, 0), 65626 }, + { conv_key(90, 0, 5120, 768, 128, 0, 0), 65618 }, + { conv_key(90, 0, 7680, 1088, 32, 0, 0), 65603 }, + { conv_key(90, 0, 7680, 1088, 64, 0, 0), 65624 }, + { conv_key(90, 0, 7680, 1088, 128, 0, 0), 65558 }, + { conv_key(90, 0, 7680, 1088, 192, 0, 0), 65621 }, + { conv_key(90, 0, 10240, 1440, 48, 0, 0), 65651 }, + { conv_key(90, 0, 10240, 1440, 64, 0, 0), 65641 }, + { conv_key(90, 0, 10240, 1440, 96, 0, 0), 65577 }, + { conv_key(90, 0, 10240, 1440, 128, 0, 0), 65567 }, + { conv_key(90, 0, 15360, 2160, 128, 0, 0), 65634 }, + { conv_key(90, 0, 15360, 2160, 192, 0, 0), 65627 }, + { conv_key(90, 0, 15360, 2176, 32, 0, 0), 65675 }, + { conv_key(90, 0, 15360, 2176, 48, 0, 0), 65653 }, + { conv_key(90, 0, 15360, 2176, 64, 0, 0), 65600 }, + { conv_key(90, 0, 15360, 2176, 96, 0, 0), 65653 }, + { conv_key(90, 0, 15360, 2176, 128, 0, 0), 65634 }, + { conv_key(90, 0, 30720, 4320, 48, 0, 0), 65675 }, + { conv_key(90, 0, 30720, 4320, 64, 0, 0), 65657 }, + { conv_key(90, 0, 30720, 4320, 96, 0, 0), 65641 }, + { conv_key(90, 0, 30720, 4320, 128, 0, 0), 65635 }, + { conv_key(90, 7, 4, 64, 64, 0, 0), 6 }, + { conv_key(90, 7, 4, 128, 128, 0, 0), 2 }, + { conv_key(90, 13, 8, 64, 64, 0, 0), 10 }, + { conv_key(90, 13, 8, 128, 128, 0, 0), 6 }, + { conv_key(90, 14, 8, 64, 64, 0, 0), 5 }, + { conv_key(90, 14, 8, 128, 128, 0, 0), 6 }, + { conv_key(90, 14, 8, 256, 256, 0, 0), 10 }, + { conv_key(90, 20, 12, 64, 64, 0, 0), 6 }, + { conv_key(90, 20, 12, 128, 128, 0, 0), 0 }, + { conv_key(90, 26, 15, 128, 128, 0, 0), 10 }, + { conv_key(90, 26, 15, 192, 192, 0, 0), 6 }, + { conv_key(90, 26, 15, 512, 512, 0, 0), 10 }, + { conv_key(90, 26, 15, 768, 768, 0, 0), 65542 }, + { conv_key(90, 26, 16, 64, 64, 0, 0), 10 }, + { conv_key(90, 26, 16, 128, 128, 0, 0), 10 }, + { conv_key(90, 26, 16, 256, 256, 0, 0), 0 }, + { conv_key(90, 28, 16, 64, 64, 0, 0), 10 }, + { conv_key(90, 28, 16, 128, 128, 0, 0), 10 }, + { conv_key(90, 28, 16, 256, 256, 0, 0), 0 }, + { conv_key(90, 28, 16, 512, 512, 0, 0), 0 }, + { conv_key(90, 30, 17, 64, 64, 0, 0), 10 }, + { conv_key(90, 30, 17, 128, 128, 0, 0), 10 }, + { conv_key(90, 40, 24, 64, 64, 0, 0), 10 }, + { conv_key(90, 40, 24, 128, 128, 0, 0), 10 }, + { conv_key(90, 40, 24, 256, 256, 0, 0), 10 }, + { conv_key(90, 52, 30, 128, 128, 0, 0), 10 }, + { conv_key(90, 52, 30, 192, 192, 0, 0), 65636 }, + { conv_key(90, 52, 30, 256, 256, 0, 0), 65635 }, + { conv_key(90, 52, 30, 384, 384, 0, 0), 65625 }, + { conv_key(90, 52, 30, 512, 512, 0, 0), 65618 }, + { conv_key(90, 52, 30, 768, 768, 0, 0), 65616 }, + { conv_key(90, 52, 32, 64, 64, 0, 0), 0 }, + { conv_key(90, 52, 32, 128, 128, 0, 0), 0 }, + { conv_key(90, 52, 32, 256, 256, 0, 0), 65633 }, + { conv_key(90, 52, 32, 512, 512, 0, 0), 65618 }, + { conv_key(90, 60, 34, 64, 64, 0, 0), 0 }, + { conv_key(90, 60, 34, 128, 128, 0, 0), 0 }, + { conv_key(90, 60, 34, 256, 256, 0, 0), 65631 }, + { conv_key(90, 80, 45, 128, 128, 0, 0), 65644 }, + { conv_key(90, 80, 45, 192, 192, 0, 0), 65626 }, + { conv_key(90, 80, 45, 512, 512, 0, 0), 65618 }, + { conv_key(90, 80, 45, 768, 768, 0, 0), 65621 }, + { conv_key(90, 80, 48, 64, 64, 0, 0), 0 }, + { conv_key(90, 80, 48, 128, 128, 0, 0), 65646 }, + { conv_key(90, 80, 48, 256, 256, 0, 0), 65626 }, + { conv_key(90, 80, 48, 512, 512, 0, 0), 65618 }, + { conv_key(90, 104, 60, 128, 128, 0, 0), 65637 }, + { conv_key(90, 104, 60, 192, 192, 0, 0), 65628 }, + { conv_key(90, 104, 60, 256, 256, 0, 0), 65637 }, + { conv_key(90, 104, 60, 384, 384, 0, 0), 65621 }, + { conv_key(90, 104, 60, 512, 512, 0, 0), 65624 }, + { conv_key(90, 120, 68, 64, 64, 0, 0), 65604 }, + { conv_key(90, 120, 68, 128, 128, 0, 0), 65603 }, + { conv_key(90, 120, 68, 192, 192, 0, 0), 65648 }, + { conv_key(90, 120, 68, 256, 256, 0, 0), 65624 }, + { conv_key(90, 120, 68, 512, 512, 0, 0), 65558 }, + { conv_key(90, 120, 68, 768, 768, 0, 0), 65621 }, + { conv_key(90, 160, 90, 128, 128, 0, 0), 65672 }, + { conv_key(90, 160, 90, 192, 192, 0, 0), 65651 }, + { conv_key(90, 160, 90, 256, 256, 0, 0), 65597 }, + { conv_key(90, 160, 90, 384, 384, 0, 0), 65578 }, + { conv_key(90, 160, 90, 512, 512, 0, 0), 65566 }, + { conv_key(90, 240, 135, 128, 128, 0, 0), 65675 }, + { conv_key(90, 240, 135, 192, 192, 0, 0), 65653 }, + { conv_key(90, 240, 135, 512, 512, 0, 0), 65634 }, + { conv_key(90, 240, 135, 768, 768, 0, 0), 65626 }, + { conv_key(90, 240, 136, 64, 64, 0, 0), 65675 }, + { conv_key(90, 240, 136, 128, 128, 0, 0), 65676 }, + { conv_key(90, 240, 136, 192, 192, 0, 0), 65653 }, + { conv_key(90, 240, 136, 256, 256, 0, 0), 65601 }, + { conv_key(90, 240, 136, 384, 384, 0, 0), 65653 }, + { conv_key(90, 240, 136, 512, 512, 0, 0), 65632 }, + { conv_key(90, 480, 270, 128, 128, 0, 0), 65675 }, + { conv_key(90, 480, 270, 192, 192, 0, 0), 65675 }, + { conv_key(90, 480, 270, 256, 256, 0, 0), 65657 }, + { conv_key(90, 480, 270, 384, 384, 0, 0), 65643 }, + { conv_key(90, 480, 270, 512, 512, 0, 0), 65634 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 0, 1280, 192, 32, 0, 0), 0 }, + { conv_key(100, 0, 1920, 272, 32, 0, 0), 1 }, + { conv_key(100, 0, 2560, 384, 32, 0, 0), 65571 }, + { conv_key(100, 0, 2560, 384, 64, 0, 0), 65553 }, + { conv_key(100, 0, 3840, 544, 32, 0, 0), 65565 }, + { conv_key(100, 0, 3840, 544, 64, 0, 0), 65570 }, + { conv_key(100, 0, 5120, 720, 128, 0, 0), 65566 }, + { conv_key(100, 0, 5120, 720, 192, 0, 0), 65621 }, + { conv_key(100, 0, 5120, 768, 32, 0, 0), 65571 }, + { conv_key(100, 0, 5120, 768, 64, 0, 0), 65628 }, + { conv_key(100, 0, 5120, 768, 128, 0, 0), 65569 }, + { conv_key(100, 0, 7680, 1088, 32, 0, 0), 65647 }, + { conv_key(100, 0, 7680, 1088, 64, 0, 0), 65554 }, + { conv_key(100, 0, 7680, 1088, 128, 0, 0), 65627 }, + { conv_key(100, 0, 7680, 1088, 192, 0, 0), 65554 }, + { conv_key(100, 0, 10240, 1440, 48, 0, 0), 65653 }, + { conv_key(100, 0, 10240, 1440, 64, 0, 0), 65568 }, + { conv_key(100, 0, 10240, 1440, 96, 0, 0), 65635 }, + { conv_key(100, 0, 10240, 1440, 128, 0, 0), 65628 }, + { conv_key(100, 0, 15360, 2160, 128, 0, 0), 65647 }, + { conv_key(100, 0, 15360, 2160, 192, 0, 0), 65635 }, + { conv_key(100, 0, 15360, 2176, 32, 0, 0), 65666 }, + { conv_key(100, 0, 15360, 2176, 48, 0, 0), 65654 }, + { conv_key(100, 0, 15360, 2176, 64, 0, 0), 65647 }, + { conv_key(100, 0, 15360, 2176, 96, 0, 0), 65659 }, + { conv_key(100, 0, 15360, 2176, 128, 0, 0), 65572 }, + { conv_key(100, 0, 30720, 4320, 48, 0, 0), 65684 }, + { conv_key(100, 0, 30720, 4320, 64, 0, 0), 65684 }, + { conv_key(100, 0, 30720, 4320, 96, 0, 0), 65658 }, + { conv_key(100, 0, 30720, 4320, 128, 0, 0), 65647 }, + { conv_key(100, 7, 4, 64, 64, 0, 0), 10 }, + { conv_key(100, 7, 4, 128, 128, 0, 0), 11 }, + { conv_key(100, 13, 8, 64, 64, 0, 0), 3 }, + { conv_key(100, 13, 8, 128, 128, 0, 0), 15 }, + { conv_key(100, 14, 8, 64, 64, 0, 0), 10 }, + { conv_key(100, 14, 8, 128, 128, 0, 0), 3 }, + { conv_key(100, 14, 8, 256, 256, 0, 0), 8 }, + { conv_key(100, 20, 12, 64, 64, 0, 0), 15 }, + { conv_key(100, 20, 12, 128, 128, 0, 0), 1 }, + { conv_key(100, 26, 15, 128, 128, 0, 0), 15 }, + { conv_key(100, 26, 15, 192, 192, 0, 0), 1 }, + { conv_key(100, 26, 15, 512, 512, 0, 0), 5 }, + { conv_key(100, 26, 15, 768, 768, 0, 0), 5 }, + { conv_key(100, 26, 16, 64, 64, 0, 0), 15 }, + { conv_key(100, 26, 16, 128, 128, 0, 0), 15 }, + { conv_key(100, 26, 16, 256, 256, 0, 0), 1 }, + { conv_key(100, 28, 16, 64, 64, 0, 0), 0 }, + { conv_key(100, 28, 16, 128, 128, 0, 0), 15 }, + { conv_key(100, 28, 16, 256, 256, 0, 0), 3 }, + { conv_key(100, 28, 16, 512, 512, 0, 0), 1 }, + { conv_key(100, 30, 17, 64, 64, 0, 0), 5 }, + { conv_key(100, 30, 17, 128, 128, 0, 0), 15 }, + { conv_key(100, 40, 24, 64, 64, 0, 0), 6 }, + { conv_key(100, 40, 24, 128, 128, 0, 0), 4 }, + { conv_key(100, 40, 24, 256, 256, 0, 0), 3 }, + { conv_key(100, 52, 30, 128, 128, 0, 0), 15 }, + { conv_key(100, 52, 30, 192, 192, 0, 0), 15 }, + { conv_key(100, 52, 30, 256, 256, 0, 0), 0 }, + { conv_key(100, 52, 30, 384, 384, 0, 0), 6 }, + { conv_key(100, 52, 30, 512, 512, 0, 0), 65638 }, + { conv_key(100, 52, 30, 768, 768, 0, 0), 65569 }, + { conv_key(100, 52, 32, 64, 64, 0, 0), 6 }, + { conv_key(100, 52, 32, 128, 128, 0, 0), 6 }, + { conv_key(100, 52, 32, 256, 256, 0, 0), 5 }, + { conv_key(100, 52, 32, 512, 512, 0, 0), 65629 }, + { conv_key(100, 60, 34, 64, 64, 0, 0), 6 }, + { conv_key(100, 60, 34, 128, 128, 0, 0), 0 }, + { conv_key(100, 60, 34, 256, 256, 0, 0), 15 }, + { conv_key(100, 80, 45, 128, 128, 0, 0), 5 }, + { conv_key(100, 80, 45, 192, 192, 0, 0), 65570 }, + { conv_key(100, 80, 45, 512, 512, 0, 0), 65566 }, + { conv_key(100, 80, 45, 768, 768, 0, 0), 65560 }, + { conv_key(100, 80, 48, 64, 64, 0, 0), 0 }, + { conv_key(100, 80, 48, 128, 128, 0, 0), 20 }, + { conv_key(100, 80, 48, 256, 256, 0, 0), 65588 }, + { conv_key(100, 80, 48, 512, 512, 0, 0), 65582 }, + { conv_key(100, 104, 60, 128, 128, 0, 0), 65598 }, + { conv_key(100, 104, 60, 192, 192, 0, 0), 65679 }, + { conv_key(100, 104, 60, 256, 256, 0, 0), 65599 }, + { conv_key(100, 104, 60, 384, 384, 0, 0), 65571 }, + { conv_key(100, 104, 60, 512, 512, 0, 0), 65568 }, + { conv_key(100, 120, 68, 64, 64, 0, 0), 5 }, + { conv_key(100, 120, 68, 128, 128, 0, 0), 65581 }, + { conv_key(100, 120, 68, 192, 192, 0, 0), 65607 }, + { conv_key(100, 120, 68, 256, 256, 0, 0), 65686 }, + { conv_key(100, 120, 68, 512, 512, 0, 0), 65570 }, + { conv_key(100, 120, 68, 768, 768, 0, 0), 65559 }, + { conv_key(100, 160, 90, 128, 128, 0, 0), 65601 }, + { conv_key(100, 160, 90, 192, 192, 0, 0), 65602 }, + { conv_key(100, 160, 90, 256, 256, 0, 0), 65602 }, + { conv_key(100, 160, 90, 384, 384, 0, 0), 65596 }, + { conv_key(100, 160, 90, 512, 512, 0, 0), 65563 }, + { conv_key(100, 240, 135, 128, 128, 0, 0), 65607 }, + { conv_key(100, 240, 135, 192, 192, 0, 0), 65608 }, + { conv_key(100, 240, 135, 512, 512, 0, 0), 65572 }, + { conv_key(100, 240, 135, 768, 768, 0, 0), 65565 }, + { conv_key(100, 240, 136, 64, 64, 0, 0), 65682 }, + { conv_key(100, 240, 136, 128, 128, 0, 0), 65607 }, + { conv_key(100, 240, 136, 192, 192, 0, 0), 65606 }, + { conv_key(100, 240, 136, 256, 256, 0, 0), 65591 }, + { conv_key(100, 240, 136, 384, 384, 0, 0), 65572 }, + { conv_key(100, 240, 136, 512, 512, 0, 0), 65572 }, + { conv_key(100, 480, 270, 128, 128, 0, 0), 65609 }, + { conv_key(100, 480, 270, 192, 192, 0, 0), 65684 }, + { conv_key(100, 480, 270, 256, 256, 0, 0), 65665 }, + { conv_key(100, 480, 270, 384, 384, 0, 0), 65647 }, + { conv_key(100, 480, 270, 512, 512, 0, 0), 65638 }, +#endif +}; + +at::Tensor d3x3(const int sm, const at::Tensor& feature, const at::Tensor& weight, at::Tensor& out_buf) +{ + return d3x3_launch_helper(sm, feature, weight, out_buf, HINT_MAP_D3x3, HINT_MAP_D3x3_NAME); +} diff --git a/src/layers/extensions/inference/cutlass/d3x3_kernel.h b/src/layers/extensions/inference/cutlass/d3x3_kernel.h new file mode 100644 index 0000000..c8b5f7f --- /dev/null +++ b/src/layers/extensions/inference/cutlass/d3x3_kernel.h @@ -0,0 +1,596 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +// clang-format on + +#include "cutlass_epilogue.h" +#include "cutlass_helper_d3x3.h" +#include "../common_cu.h" +#include "../def_cutlass.h" + +static constexpr int CUTLASS_START_INDEX = 65536; +static constexpr int HINT_NUM_CUTLASS = 151; +static constexpr int HINT_NUM_CUDA = 25; + +template +at::Tensor d3x3_cutlass(const at::Tensor& feature, const at::Tensor& weight, const at::Tensor& out_buf) +{ + static constexpr int groups_per_cta = 64; + using ThreadBlockOutputShape = cutlass::conv::TensorNHWCShape<1, 8, 8, groups_per_cta>; + using FilterShape = cutlass::MatrixShape<3, 3>; + using ThreadblockShape = + cutlass::gemm::GemmShape; + using WarpShape = cutlass::gemm::GemmShape<16, groups_per_cta, FilterShape::kCount>; + using InstructionShape = cutlass::gemm::GemmShape<1, 1, 1>; + using SwizzleThreadBlock = + cutlass::conv::threadblock::DepthwiseDirect2dConvIdentityThreadblockSwizzle< + 1, ThreadBlockOutputShape::kN, ThreadBlockOutputShape::kH, ThreadBlockOutputShape::kW>; + using StrideShape = cutlass::MatrixShape<1, 1>; + using DilationShape = cutlass::MatrixShape<1, 1>; + + using EpilogueOp = cutlass::epilogue::thread::LinearCombination< + cutlass::half_t, // Data type of output matrix. + 128 / cutlass::sizeof_bits_v, // The number of elements per vectorized. + cutlass::half_t, // Data type of accumulator + cutlass::half_t, // Data type for alpha/beta in linear combination + cutlass::epilogue::thread::ScaleType::Nothing>; // Epilogue scaling operation. + + using DepthwiseDirect2dConv = typename CustomDefaultDepthwiseDirect2dConvFprop< + cutlass::half_t, cutlass::layout::TensorNHWC, cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, cutlass::half_t, cutlass::arch::OpClassSimt, SmArch, + ThreadblockShape, ThreadBlockOutputShape, FilterShape, WarpShape, InstructionShape, EpilogueOp, + SwizzleThreadBlock, stages, cutlass::arch::OpMultiplyAdd, cutlass::conv::IteratorAlgorithm::kFixedStrideDilation, + cutlass::conv::StrideSupport::kFixed, StrideShape, DilationShape>::Kernel; + + using Direct2dConv = CustomDirectConvolutionDevice; + + // Note: d3x3 weight is reordered from [C, 1, 3, 3] to [1, C, 3, 3]. + const int B = feature.size(0); + const int C = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int C1_ = weight.size(0); + const int C2_ = weight.size(1); + const int KH_ = weight.size(2); + const int KW_ = weight.size(3); + assert(C == C2_ && C1_ == 1 && KH_ == 3 && KW_ == 3); + + cutlass::conv::Conv2dProblemSize problem_size({ B, H, W, C }, // input + { C, 3, 3, 1 }, // kernel + { 1, 1, 1, 1 }, // pad + { 1, 1 }, // stride + { 1, 1 }, // dilation + { B, H, W, C }, // out + cutlass::conv::Mode::kCrossCorrelation, + split_k_slices, // split_k_slices + C // groups + ); + + cutlass::TensorRef d_feature( + static_cast(feature.data_ptr()), + cutlass::make_Coord(feature.stride(3), feature.stride(2), feature.stride(0))); + cutlass::TensorRef d_weight( + static_cast(weight.data_ptr()), + cutlass::make_Coord(weight.stride(3), weight.stride(2), weight.stride(0))); + cutlass::TensorRef d_out( + static_cast(out_buf.data_ptr()), + cutlass::make_Coord(out_buf.stride(3), out_buf.stride(2), out_buf.stride(0))); + + typename Direct2dConv::Arguments args(problem_size, d_feature, d_weight, d_out, d_out, {}, d_weight); + + Direct2dConv direct2dconv_op; + cutlass::Status status = direct2dconv_op.can_implement(args); + if (status != cutlass::Status::kSuccess) { + std::cerr << "Failed to configure convolution operation." << std::endl; + return at::Tensor(); + } + + auto stream = at::cuda::getCurrentCUDAStream(); + status = direct2dconv_op(args, nullptr, stream); + if (status != cutlass::Status::kSuccess) { + std::cerr << "Failed to run convolution operation." << std::endl; + return at::Tensor(); + } + + return out_buf; +} + +template +__global__ void d3x3_kernel(GPUTensor4D out, const GPUTensor4D feature, + const GPUTensor4D weight, const int C, const int H, const int W) +{ + const int n = blockIdx.x * blockDim.x + threadIdx.x; + const int c = n % C; + const int hw = n / C; + const int h = (hw % ((H + H_BLOCK_SIZE - 1) / H_BLOCK_SIZE)) * H_BLOCK_SIZE; + const int w = (hw / ((H + H_BLOCK_SIZE - 1) / H_BLOCK_SIZE)) * W_BLOCK_SIZE; + if (c >= C || h >= H || w >= W) { + cudaGDC(); + return; + } + + float _weight[3][3]; + float _feature[H_BLOCK_SIZE + 2][W_BLOCK_SIZE + 2]; + +#pragma unroll + for (int i = 0; i < 3; i++) { +#pragma unroll + for (int j = 0; j < 3; j++) { + _weight[i][j] = static_cast(weight[0][c][i][j]); + } + } + cudaGDC(); + +#pragma unroll + for (int i = 0; i < H_BLOCK_SIZE + 2; i++) { +#pragma unroll + for (int j = 0; j < W_BLOCK_SIZE + 2; j++) { + const int y = h + i - 1; + const int x = w + j - 1; + float curr_feature = 0.f; + if (y >= 0 && y < H && x >= 0 && x < W) { + curr_feature = static_cast(feature[0][c][y][x]); + } + _feature[i][j] = curr_feature; + } + } + + for (int h_offset = 0; h_offset < H_BLOCK_SIZE; h_offset++) { + if (h + h_offset >= H) { + break; + } + for (int w_offset = 0; w_offset < W_BLOCK_SIZE; w_offset++) { + if (w + w_offset >= W) { + break; + } + + float r = 0.f; +#pragma unroll + for (int i = 0; i < 3; i++) { +#pragma unroll + for (int j = 0; j < 3; j++) { + float curr_weight = _weight[i][j]; + float curr_feature = _feature[i + h_offset][j + w_offset]; + r += curr_feature * curr_weight; + } + } + out[0][c][h + h_offset][w + w_offset] = r; + } + } +} + +template +__forceinline__ auto d3x3_launch(const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& out_buf) +{ + // Note: d3x3 weight is reordered from [C, 1, 3, 3] to [1, C, 3, 3]. + const int C = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int C1_ = weight.size(0); + const int C2_ = weight.size(1); + const int KH_ = weight.size(2); + const int KW_ = weight.size(3); + assert(C == C2_ && C1_ == 1 && KH_ == 3 && KW_ == 3); + const int total_threads = + C * ((H + H_BLOCK_SIZE - 1) / H_BLOCK_SIZE) * ((W + W_BLOCK_SIZE - 1) / W_BLOCK_SIZE); + + const int BLOCK_SIZE = 256; + const dim3 gridDim((total_threads + BLOCK_SIZE - 1) / BLOCK_SIZE); + const dim3 blockDim(BLOCK_SIZE); + + cudaLaunchConfig_t config; + config.gridDim = gridDim; + config.blockDim = blockDim; + config.dynamicSmemBytes = 0; + config.stream = at::cuda::getCurrentCUDAStream(); + auto attr = get_cuda_launch_attribute(); + config.attrs = &attr; + config.numAttrs = 1; + + cudaLaunchKernelEx(&config, &d3x3_kernel, out_buf, feature, weight, + C, H, W); + return out_buf; +} + +__forceinline__ auto d3x3_launch_switcher(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& out_buf, + const int hint) +{ + if (sm >= 80) { + /** + * 0: pytorch + * 1 - 25: cuda + * 65536 - 65686: cutlass + */ + switch (hint) { + // remove the original case 0 because "at::conv2d" does not support out_buf + case 0: + return d3x3_launch<2, 2>(feature, weight, out_buf); + case 1: + return d3x3_launch<2, 3>(feature, weight, out_buf); + case 2: + return d3x3_launch<2, 4>(feature, weight, out_buf); + case 3: + return d3x3_launch<2, 5>(feature, weight, out_buf); + case 4: + return d3x3_launch<2, 6>(feature, weight, out_buf); + case 5: + return d3x3_launch<3, 2>(feature, weight, out_buf); + case 6: + return d3x3_launch<3, 3>(feature, weight, out_buf); + case 7: + return d3x3_launch<3, 4>(feature, weight, out_buf); + case 8: + return d3x3_launch<3, 5>(feature, weight, out_buf); + case 9: + return d3x3_launch<3, 6>(feature, weight, out_buf); + case 10: + return d3x3_launch<4, 2>(feature, weight, out_buf); + case 11: + return d3x3_launch<4, 3>(feature, weight, out_buf); + case 12: + return d3x3_launch<4, 4>(feature, weight, out_buf); + case 13: + return d3x3_launch<4, 5>(feature, weight, out_buf); + case 14: + return d3x3_launch<4, 6>(feature, weight, out_buf); + case 15: + return d3x3_launch<5, 2>(feature, weight, out_buf); + case 16: + return d3x3_launch<5, 3>(feature, weight, out_buf); + case 17: + return d3x3_launch<5, 4>(feature, weight, out_buf); + case 18: + return d3x3_launch<5, 5>(feature, weight, out_buf); + case 19: + return d3x3_launch<5, 6>(feature, weight, out_buf); + case 20: + return d3x3_launch<6, 2>(feature, weight, out_buf); + case 21: + return d3x3_launch<6, 3>(feature, weight, out_buf); + case 22: + return d3x3_launch<6, 4>(feature, weight, out_buf); + case 23: + return d3x3_launch<6, 5>(feature, weight, out_buf); + case 24: + return d3x3_launch<6, 6>(feature, weight, out_buf); + case 65536: + return d3x3_cutlass(feature, weight, out_buf); + case 65537: + return d3x3_cutlass(feature, weight, out_buf); + case 65538: + return d3x3_cutlass(feature, weight, out_buf); + case 65539: + return d3x3_cutlass(feature, weight, out_buf); + case 65540: + return d3x3_cutlass(feature, weight, out_buf); + case 65541: + return d3x3_cutlass(feature, weight, out_buf); + case 65542: + return d3x3_cutlass(feature, weight, out_buf); + case 65543: + return d3x3_cutlass(feature, weight, out_buf); + case 65544: + return d3x3_cutlass(feature, weight, out_buf); + case 65545: + return d3x3_cutlass(feature, weight, out_buf); + case 65546: + return d3x3_cutlass(feature, weight, out_buf); + case 65547: + return d3x3_cutlass(feature, weight, out_buf); + case 65548: + return d3x3_cutlass(feature, weight, out_buf); + case 65549: + return d3x3_cutlass(feature, weight, out_buf); + case 65550: + return d3x3_cutlass(feature, weight, out_buf); + case 65551: + return d3x3_cutlass(feature, weight, out_buf); + case 65552: + return d3x3_cutlass(feature, weight, out_buf); + case 65553: + return d3x3_cutlass(feature, weight, out_buf); + case 65554: + return d3x3_cutlass(feature, weight, out_buf); + case 65555: + return d3x3_cutlass(feature, weight, out_buf); + case 65556: + return d3x3_cutlass(feature, weight, out_buf); + case 65557: + return d3x3_cutlass(feature, weight, out_buf); + case 65558: + return d3x3_cutlass(feature, weight, out_buf); + case 65559: + return d3x3_cutlass(feature, weight, out_buf); + case 65560: + return d3x3_cutlass(feature, weight, out_buf); + case 65561: + return d3x3_cutlass(feature, weight, out_buf); + case 65562: + return d3x3_cutlass(feature, weight, out_buf); + case 65563: + return d3x3_cutlass(feature, weight, out_buf); + case 65564: + return d3x3_cutlass(feature, weight, out_buf); + case 65565: + return d3x3_cutlass(feature, weight, out_buf); + case 65566: + return d3x3_cutlass(feature, weight, out_buf); + case 65567: + return d3x3_cutlass(feature, weight, out_buf); + case 65568: + return d3x3_cutlass(feature, weight, out_buf); + case 65569: + return d3x3_cutlass(feature, weight, out_buf); + case 65570: + return d3x3_cutlass(feature, weight, out_buf); + case 65571: + return d3x3_cutlass(feature, weight, out_buf); + case 65572: + return d3x3_cutlass(feature, weight, out_buf); + case 65573: + return d3x3_cutlass(feature, weight, out_buf); + case 65574: + return d3x3_cutlass(feature, weight, out_buf); + case 65575: + return d3x3_cutlass(feature, weight, out_buf); + case 65576: + return d3x3_cutlass(feature, weight, out_buf); + case 65577: + return d3x3_cutlass(feature, weight, out_buf); + case 65578: + return d3x3_cutlass(feature, weight, out_buf); + case 65579: + return d3x3_cutlass(feature, weight, out_buf); + case 65580: + return d3x3_cutlass(feature, weight, out_buf); + case 65581: + return d3x3_cutlass(feature, weight, out_buf); + case 65582: + return d3x3_cutlass(feature, weight, out_buf); + case 65583: + return d3x3_cutlass(feature, weight, out_buf); + case 65584: + return d3x3_cutlass(feature, weight, out_buf); + case 65585: + return d3x3_cutlass(feature, weight, out_buf); + case 65586: + return d3x3_cutlass(feature, weight, out_buf); + case 65587: + return d3x3_cutlass(feature, weight, out_buf); + case 65588: + return d3x3_cutlass(feature, weight, out_buf); + case 65589: + return d3x3_cutlass(feature, weight, out_buf); + case 65590: + return d3x3_cutlass(feature, weight, out_buf); + case 65591: + return d3x3_cutlass(feature, weight, out_buf); + case 65592: + return d3x3_cutlass(feature, weight, out_buf); + case 65593: + return d3x3_cutlass(feature, weight, out_buf); + case 65594: + return d3x3_cutlass(feature, weight, out_buf); + case 65595: + return d3x3_cutlass(feature, weight, out_buf); + case 65596: + return d3x3_cutlass(feature, weight, out_buf); + case 65597: + return d3x3_cutlass(feature, weight, out_buf); + case 65598: + return d3x3_cutlass(feature, weight, out_buf); + case 65599: + return d3x3_cutlass(feature, weight, out_buf); + case 65600: + return d3x3_cutlass(feature, weight, out_buf); + case 65601: + return d3x3_cutlass(feature, weight, out_buf); + case 65602: + return d3x3_cutlass(feature, weight, out_buf); + case 65603: + return d3x3_cutlass(feature, weight, out_buf); + case 65604: + return d3x3_cutlass(feature, weight, out_buf); + case 65605: + return d3x3_cutlass(feature, weight, out_buf); + case 65606: + return d3x3_cutlass(feature, weight, out_buf); + case 65607: + return d3x3_cutlass(feature, weight, out_buf); + case 65608: + return d3x3_cutlass(feature, weight, out_buf); + case 65609: + return d3x3_cutlass(feature, weight, out_buf); + case 65610: + return d3x3_cutlass(feature, weight, out_buf); + case 65611: + return d3x3_cutlass(feature, weight, out_buf); + case 65612: + return d3x3_cutlass(feature, weight, out_buf); + case 65613: + return d3x3_cutlass(feature, weight, out_buf); + case 65614: + return d3x3_cutlass(feature, weight, out_buf); + case 65615: + return d3x3_cutlass(feature, weight, out_buf); + case 65616: + return d3x3_cutlass(feature, weight, out_buf); + case 65617: + return d3x3_cutlass(feature, weight, out_buf); + case 65618: + return d3x3_cutlass(feature, weight, out_buf); + case 65619: + return d3x3_cutlass(feature, weight, out_buf); + case 65620: + return d3x3_cutlass(feature, weight, out_buf); + case 65621: + return d3x3_cutlass(feature, weight, out_buf); + case 65622: + return d3x3_cutlass(feature, weight, out_buf); + case 65623: + return d3x3_cutlass(feature, weight, out_buf); + case 65624: + return d3x3_cutlass(feature, weight, out_buf); + case 65625: + return d3x3_cutlass(feature, weight, out_buf); + case 65626: + return d3x3_cutlass(feature, weight, out_buf); + case 65627: + return d3x3_cutlass(feature, weight, out_buf); + case 65628: + return d3x3_cutlass(feature, weight, out_buf); + case 65629: + return d3x3_cutlass(feature, weight, out_buf); + case 65630: + return d3x3_cutlass(feature, weight, out_buf); + case 65631: + return d3x3_cutlass(feature, weight, out_buf); + case 65632: + return d3x3_cutlass(feature, weight, out_buf); + case 65633: + return d3x3_cutlass(feature, weight, out_buf); + case 65634: + return d3x3_cutlass(feature, weight, out_buf); + case 65635: + return d3x3_cutlass(feature, weight, out_buf); + case 65636: + return d3x3_cutlass(feature, weight, out_buf); + case 65637: + return d3x3_cutlass(feature, weight, out_buf); + case 65638: + return d3x3_cutlass(feature, weight, out_buf); + case 65639: + return d3x3_cutlass(feature, weight, out_buf); + case 65640: + return d3x3_cutlass(feature, weight, out_buf); + case 65641: + return d3x3_cutlass(feature, weight, out_buf); + case 65642: + return d3x3_cutlass(feature, weight, out_buf); + case 65643: + return d3x3_cutlass(feature, weight, out_buf); + case 65644: + return d3x3_cutlass(feature, weight, out_buf); + case 65645: + return d3x3_cutlass(feature, weight, out_buf); + case 65646: + return d3x3_cutlass(feature, weight, out_buf); + case 65647: + return d3x3_cutlass(feature, weight, out_buf); + case 65648: + return d3x3_cutlass(feature, weight, out_buf); + case 65649: + return d3x3_cutlass(feature, weight, out_buf); + case 65650: + return d3x3_cutlass(feature, weight, out_buf); + case 65651: + return d3x3_cutlass(feature, weight, out_buf); + case 65652: + return d3x3_cutlass(feature, weight, out_buf); + case 65653: + return d3x3_cutlass(feature, weight, out_buf); + case 65654: + return d3x3_cutlass(feature, weight, out_buf); + case 65655: + return d3x3_cutlass(feature, weight, out_buf); + case 65656: + return d3x3_cutlass(feature, weight, out_buf); + case 65657: + return d3x3_cutlass(feature, weight, out_buf); + case 65658: + return d3x3_cutlass(feature, weight, out_buf); + case 65659: + return d3x3_cutlass(feature, weight, out_buf); + case 65660: + return d3x3_cutlass(feature, weight, out_buf); + case 65661: + return d3x3_cutlass(feature, weight, out_buf); + case 65662: + return d3x3_cutlass(feature, weight, out_buf); + case 65663: + return d3x3_cutlass(feature, weight, out_buf); + case 65664: + return d3x3_cutlass(feature, weight, out_buf); + case 65665: + return d3x3_cutlass(feature, weight, out_buf); + case 65666: + return d3x3_cutlass(feature, weight, out_buf); + case 65667: + return d3x3_cutlass(feature, weight, out_buf); + case 65668: + return d3x3_cutlass(feature, weight, out_buf); + case 65669: + return d3x3_cutlass(feature, weight, out_buf); + case 65670: + return d3x3_cutlass(feature, weight, out_buf); + case 65671: + return d3x3_cutlass(feature, weight, out_buf); + case 65672: + return d3x3_cutlass(feature, weight, out_buf); + case 65673: + return d3x3_cutlass(feature, weight, out_buf); + case 65674: + return d3x3_cutlass(feature, weight, out_buf); + case 65675: + return d3x3_cutlass(feature, weight, out_buf); + case 65676: + return d3x3_cutlass(feature, weight, out_buf); + case 65677: + return d3x3_cutlass(feature, weight, out_buf); + case 65678: + return d3x3_cutlass(feature, weight, out_buf); + case 65679: + return d3x3_cutlass(feature, weight, out_buf); + case 65680: + return d3x3_cutlass(feature, weight, out_buf); + case 65681: + return d3x3_cutlass(feature, weight, out_buf); + case 65682: + return d3x3_cutlass(feature, weight, out_buf); + case 65683: + return d3x3_cutlass(feature, weight, out_buf); + case 65684: + return d3x3_cutlass(feature, weight, out_buf); + case 65685: + return d3x3_cutlass(feature, weight, out_buf); + case 65686: // default cutlass hint for sm80 + return d3x3_cutlass(feature, weight, out_buf); + default: + assert(false); + } + } + + assert(sm == 75); + return d3x3_cutlass(feature, weight, out_buf); +} + +__forceinline__ auto d3x3_launch_helper(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& out_buf, + std::unordered_map& map, + const std::string& map_name) +{ + if (sm == 75) { + return d3x3_launch_switcher(sm, feature, weight, out_buf, -1); + } + const int C = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const uint64_t key = conv_key(sm, W, H, C, C, 0, 0); + int best_hint = -1; + auto it = map.find(key); + if (it == map.end()) { + return d3x3_launch_switcher(sm, feature, weight, out_buf, + CUTLASS_START_INDEX + HINT_NUM_CUTLASS - 1); + } else { + best_hint = it->second; + } + return d3x3_launch_switcher(sm, feature, weight, out_buf, best_hint); +} diff --git a/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_builder_epilogue.h b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_builder_epilogue.h new file mode 100644 index 0000000..d93b0ff --- /dev/null +++ b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_builder_epilogue.h @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +// clang-format on + +#include "sm90_epilogue_tma_warpspecialized_quad.h" + +/** + * These 2 classes/structs are rewritten: + * 1. cutlass::epilogue::collective::detail::Sm90TmaBuilderImpl -> QuadSm90TmaBuilderImpl + * 2. cutlass::epilogue::collective::CollectiveBuilder -> QuadCollectiveBuilderEpilogue + */ + +// Original file: cutlass/epilogue/collective/builders/sm90_builder.inl +// to define QuadCollectiveEpilogue as CollectiveOp +// Helper for building TMA warp-specialized collective epilogues, specialized by +// the fusion operation performed and the dispatch policy to use. +template +struct QuadSm90TmaBuilderImpl { + // C/D should meet TMA alignment requirement if not void + static_assert( + cutlass::epilogue::collective::detail::is_aligned(), + "C/D Should meet TMA alignment requirement\n"); + // Passing void D disables destination store + smem allocation + using ElementD = + cute::conditional_t, + cutlass::epilogue::fusion::get_element_aux_t, ElementD_>; + + // Passing void C disables source load + smem allocation + using ElementC = + cute::conditional_t, ElementD, ElementC_>; // prevents void ref breakages + using GmemLayoutTagC = + cute::conditional_t, GmemLayoutTagD, GmemLayoutTagC_>; + + using GmemStrideTypeC = cutlass::detail::TagToStrideC_t; + using GmemStrideTypeD = cutlass::detail::TagToStrideC_t; + + using UnderlyingGmemStrideTypeC = cute::remove_pointer_t; + using UnderlyingGmemStrideTypeD = cute::remove_pointer_t; + + using CopyOpS2G = + cute::conditional_t, + cute::SM90_TMA_STORE_IM2COL, cute::SM90_TMA_STORE>; + using CopyOpG2S = + cute::conditional_t, + cute::SM90_TMA_LOAD_IM2COL, cute::SM90_TMA_LOAD>; + + // Get the smallest tiled copy we can use to retile the accumulators + // using CopyAtomC = Copy_Atom; + using CopyAtomC = cute::conditional_t< + cute::size<1>(EpilogueTile_MN{}) % 16 == 0, cute::Copy_Atom, + cute::conditional_t(EpilogueTile_MN{}) % 8 == 0, + cute::Copy_Atom, void>>; + static_assert(!cute::is_same_v, + "CopyAtomC can't be void, divisiblity check for EpilogueTile_MN failed"); + // Get register to register tiled copy that happen before shared memory store. + // Apply void as no register transform op needed currently. + using CopyOpR2R = void; + + // TMA builder allows for passing callbacks directly, which is either a cutlass::epilogue::fusion::FusionCallbacks + // instance or a direct visitor implementation, e.g. cutlass::epilogue::fusion::Sm90LinearCombination + using FusionCallbacks = typename cutlass::epilogue::collective::detail::CallbacksBuilder< + DispatchPolicy, FusionOpOrCallbacks, TileShape_MNK, EpilogueTile_MN, ElementAccumulator>::Callbacks; + + using CollectiveOp = QuadCollectiveEpilogue< + DispatchPolicy, TileShape_MNK, EpilogueTile_MN, + ElementC_, // Need to pass void through to expose via QuadGemmUniversal + GmemStrideTypeC, ElementD_, GmemStrideTypeD, FusionCallbacks, CopyOpG2S, + decltype(cutlass::epilogue::collective::detail::sm90_get_epilogue_smem_swizzle_layout_atom< + UnderlyingGmemStrideTypeC, ElementC, EpilogueTile_MN>()), + decltype(cutlass::epilogue::collective::detail::sm90_get_smem_load_op_for_source< + UnderlyingGmemStrideTypeC, ElementC, EpilogueTile_MN>()), + CopyOpS2G, + decltype(cutlass::epilogue::collective::detail::sm90_get_epilogue_smem_swizzle_layout_atom< + UnderlyingGmemStrideTypeD, ElementD, EpilogueTile_MN>()), + decltype(cutlass::epilogue::collective::detail::sm90_get_smem_store_op_for_accumulator< + UnderlyingGmemStrideTypeD, ElementD, EpilogueTile_MN>()), + CopyAtomC, CopyOpR2R>; +}; + +// Primary template declaration to enable partial/specialized definitions below. +template , + class Enable = void> +struct QuadCollectiveBuilderEpilogue { + static_assert(cutlass::detail::dependent_false, + "Could not build a collective epilogue for given parameters."); +}; + +// Original file: cutlass/epilogue/collective/builders/sm90_builder.inl +// to define QuadSm90TmaBuilderImpl as CollectiveOp +// Tma warp-specialized builder +template +struct QuadCollectiveBuilderEpilogue< + cutlass::arch::Sm90, OpClass, TileShape_MNK, ClusterShape_MNK, EpilogueTileType, ElementAccumulator, ElementCompute, + ElementC, GmemLayoutTagC, AlignmentC, ElementD_, GmemLayoutTagD, AlignmentD, Schedule, FusionOperation, + cute::enable_if_t>> { +private: + using ElementD = + cute::conditional_t, + cutlass::epilogue::fusion::get_element_aux_t, ElementD_>; + using EpilogueTile_MN = + decltype(cutlass::epilogue::collective::detail::sm90_compute_tile_shape_or_override< + ElementD, EpilogueTileType, Schedule, TileShape_MNK>()); + using DispatchPolicy = decltype(cutlass::epilogue::collective::detail::sm90_get_tma_dispatch_policy< + TileShape_MNK, EpilogueTile_MN, ElementC, ElementD, Schedule>()); + +public: + using CollectiveOp = + typename QuadSm90TmaBuilderImpl::CollectiveOp; +}; diff --git a/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_builder_mainloop.h b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_builder_mainloop.h new file mode 100644 index 0000000..26b8d24 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_builder_mainloop.h @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +// clang-format on + +#include "sm90_mma_tma_gmma_ss_warpspecialized_quad.h" + +/** + * These 1 classes/structs are rewritten: + * 1. cutlass::gemm::collective::CollectiveBuilder -> QuadCollectiveBuilderMainloop + */ + +// SM90 Collective Builders should be used only starting CUDA 12.0 +#if (__CUDACC_VER_MAJOR__ >= 12) + #define CUTLASS_SM90_COLLECTIVE_BUILDER_SUPPORTED +#endif + +// Primary template declaration to enable partial/specialized definitions below. +template +struct QuadCollectiveBuilderMainloop { + static_assert(sizeof(ElementA) == 0, + "QuadCollectiveBuilderMainloop: unsupported configuration."); +}; + +// Original file: cutlass/gemm/collective/builders/sm90_gmma_builder.inl +// to define QuadCollectiveMma as CollectiveOp +// GMMA_TMA_WS_SS +template +struct QuadCollectiveBuilderMainloop< + cutlass::arch::Sm90, cutlass::arch::OpClassTensorOp, ElementA, GmemLayoutATag, AlignmentA, ElementB, + GmemLayoutBTag, AlignmentB, ElementAccumulator, TileShape_MNK, ClusterShape_MNK, StageCountType, KernelScheduleType, + cute::enable_if_t<(cute::is_same_v) + && not cutlass::gemm::collective::detail::is_use_rmem_A< + ElementA, GmemLayoutATag, ElementB, GmemLayoutBTag>()>> { + static_assert(cute::is_static::value); + static_assert(cute::is_static::value); +#ifndef CUTLASS_SM90_COLLECTIVE_BUILDER_SUPPORTED + static_assert(cutlass::detail::dependent_false, + "Unsupported Toolkit for SM90 Collective Builder\n"); +#endif + static_assert( + cutlass::gemm::collective::detail::is_aligned(), + "Should meet TMA alignment requirement\n"); + + using ElementAMma = + cute::conditional_t, cutlass::tfloat32_t, ElementA>; + using ElementBMma = + cute::conditional_t, cutlass::tfloat32_t, ElementB>; + + static constexpr cute::GMMA::Major GmmaMajorA = + cutlass::gemm::collective::detail::gmma_ss_tag_to_major_A(); + static constexpr cute::GMMA::Major GmmaMajorB = + cutlass::gemm::collective::detail::gmma_ss_tag_to_major_B(); + + static constexpr bool IsCooperative = + cute::is_same_v; + using AtomLayoutMNK = + cute::conditional_t>, + cute::Layout>>; + + using TiledMma = decltype(cute::make_tiled_mma( + cute::GMMA::ss_op_selector(), + AtomLayoutMNK{})); + + using GmemTiledCopyA = decltype(cutlass::gemm::collective::detail::sm90_cluster_shape_to_tma_atom( + cute::shape<1>(ClusterShape_MNK{}))); + using GmemTiledCopyB = decltype(cutlass::gemm::collective::detail::sm90_cluster_shape_to_tma_atom( + cute::shape<0>(ClusterShape_MNK{}))); + + using SmemLayoutAtomA = decltype(cutlass::gemm::collective::detail::ss_smem_selector< + GmmaMajorA, ElementAMma, decltype(cute::get<0>(TileShape_MNK{})), + decltype(cute::get<2>(TileShape_MNK{}))>()); + using SmemLayoutAtomB = decltype(cutlass::gemm::collective::detail::ss_smem_selector< + GmmaMajorB, ElementBMma, decltype(cute::get<1>(TileShape_MNK{})), + decltype(cute::get<2>(TileShape_MNK{}))>()); + + static constexpr size_t TensorMapStorage = 0; + static constexpr size_t SchedulerPipelineStorage = + cute::is_pointer_v> + ? sizeof(cutlass::PipelineDetail::PipelineAsyncSharedStorage<8>) + : 0; + static constexpr int KernelSmemCarveout = + static_cast(TensorMapStorage + SchedulerPipelineStorage); + static constexpr int Sm90ReducedSmemCapacityBytes = + cutlass::gemm::collective::detail::sm90_smem_capacity_bytes - KernelSmemCarveout; + + static constexpr int PipelineStages = + cutlass::gemm::collective::detail::compute_stage_count_or_override< + Sm90ReducedSmemCapacityBytes, ElementAMma, ElementBMma, TileShape_MNK>(StageCountType{}); + + using DispatchPolicy = + cutlass::gemm::MainloopSm90TmaGmmaWarpSpecialized; + + using SmemCopyAtomA = void; + using SmemCopyAtomB = void; + + using CollectiveOp = QuadCollectiveMma< + DispatchPolicy, TileShape_MNK, ElementA, cutlass::detail::TagToStrideA_t, ElementB, + cutlass::detail::TagToStrideB_t, TiledMma, GmemTiledCopyA, SmemLayoutAtomA, + SmemCopyAtomA, cute::identity, GmemTiledCopyB, SmemLayoutAtomB, SmemCopyAtomB, cute::identity>; +}; diff --git a/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_epilogue_tma_warpspecialized_quad.h b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_epilogue_tma_warpspecialized_quad.h new file mode 100644 index 0000000..f07db07 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_epilogue_tma_warpspecialized_quad.h @@ -0,0 +1,992 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +// clang-format on + +/** + * These 1 classes/structs are rewritten: + * 1. cutlass::epilogue::collective::CollectiveEpilogue -> QuadCollectiveEpilogue + */ + +template +struct QuadAddOp; + +template +struct QuadAddOp> { + static const bool kIsHeavy = true; + + CUTLASS_HOST_DEVICE + cutlass::Array operator()(cutlass::Array const& accum0, + cutlass::Array const& accum1, + cutlass::Array const& accum2, + cutlass::Array const& accum3) const + { + cutlass::plus> plus_op; + return plus_op(plus_op(plus_op(accum0, accum1), accum2), accum3); + } +}; + +// Primary template declaration to enable partial/specialized definitions below. +template +class QuadCollectiveEpilogue { + static_assert(cutlass::detail::dependent_false, + "Could not find an epilogue specialization."); +}; + +// Original file: cutlass/epilogue/collective/sm90_epilogue_tma_warpspecialized.hpp +// to define QuadCollectiveEpilogue as CollectiveOp +template +class QuadCollectiveEpilogue< + cutlass::epilogue::Sm90TmaWarpSpecialized, + CtaTileMNK_, EpilogueTile_, ElementC_, StrideC_, ElementD_, StrideD_, FusionCallbacks_, CopyOpG2S_, + SmemLayoutAtomC_, CopyOpS2R_, CopyOpS2G_, SmemLayoutAtomD_, CopyOpR2S_, CopyAtomC_, CopyOpR2R_> { +public: + // + // Type Aliases + // + using DispatchPolicy = + cutlass::epilogue::Sm90TmaWarpSpecialized; + using CtaTileMNK = CtaTileMNK_; + using EpilogueTile = EpilogueTile_; + using FusionCallbacks = FusionCallbacks_; + using ElementC = ElementC_; + using StrideC = StrideC_; + using ElementD = ElementD_; + using StrideD = StrideD_; + using CopyOpG2S = CopyOpG2S_; + using SmemLayoutAtomC = SmemLayoutAtomC_; + using CopyOpS2R = CopyOpS2R_; + using CopyOpS2G = CopyOpS2G_; + using SmemLayoutAtomD = SmemLayoutAtomD_; + using CopyOpR2S = CopyOpR2S_; + using CopyAtomC = CopyAtomC_; + using CopyOpR2R = CopyOpR2R_; + + using ThreadEpilogueOp = + typename cutlass::epilogue::fusion::FusionCallbacksTraits::Operation; + using GmemTiledCopyC = CopyOpG2S; + using GmemTiledCopyD = CopyOpS2G; + + static_assert(!cute::is_layout::value && cutlass::is_tuple::value, + "EpilogueTile must be a cute::Tile or cute::Shape"); + static_assert(cute::rank(CtaTileMNK{}) == 3, + "CtaTileMNK must be rank-3: [CTA_M, CTA_N, CTA_K]"); + static_assert(cute::rank(EpilogueTile{}) == 2, + "EpilogueTile must be rank-2: [EPI_TILE_M, EPI_TILE_N]"); + static_assert(cute::size<0>(CtaTileMNK{}) % cute::size<0>(cute::shape(EpilogueTile{})) == 0, + "EPI_TILE_M must divide CTA_M"); + static_assert(cute::size<1>(CtaTileMNK{}) % cute::size<1>(cute::shape(EpilogueTile{})) == 0, + "EPI_TILE_N must divide CTA_N"); + static_assert(cute::rank(StrideC{}) == 3, "StrideC must be rank-3: [M, N, L]"); + static_assert(cute::rank(StrideD{}) == 3, "StrideD must be rank-3: [M, N, L]"); + +private: + constexpr static bool is_source_supported = not cute::is_void_v; + constexpr static bool is_destination_supported = not cute::is_void_v; + using NonVoidElementD = + cute::conditional_t, ElementD>; + static_assert(not cute::is_void_v, "SmemElementD is void"); + using NonVoidElementC = cute::conditional_t; // prevents void ref breakages + + using TmaElementD = + cute::conditional_t>, uint64_t, NonVoidElementD>; + using TmaElementC = + cute::conditional_t>, uint64_t, NonVoidElementC>; + + using SmemElementC = typename cutlass::detail::get_unpacked_element_type::type; + using SmemElementD = typename cutlass::detail::get_unpacked_element_type::type; + + constexpr static int StagesC = StagesC_; + constexpr static int StagesD = StagesD_; + constexpr static bool ReuseSmemC = ReuseSmemC_ and is_destination_supported; + constexpr static bool DelayTmaStore = DelayTmaStore_; + + constexpr static bool is_m_major_C = cutlass::epilogue::collective::detail::is_m_major(); + constexpr static bool is_m_major_D = cutlass::epilogue::collective::detail::is_m_major(); + + constexpr static bool is_im2col_C = cute::is_same_v; + constexpr static bool is_im2col_D = cute::is_same_v; + + // Check if register transformation is needed before copying register to shared memory. + constexpr static bool IsUseR2R = !cute::is_void_v; + + using SmemLayoutC = decltype(cute::tile_to_shape( + SmemLayoutAtomC{}, + cute::make_shape(cute::size<0>(EpilogueTile{}), cute::size<1>(EpilogueTile{}), + cute::Int{}), + cute::conditional_t, + cute::Step>{})); + using SmemLayoutD = decltype(cute::tile_to_shape( + SmemLayoutAtomD{}, + cute::make_shape(cute::size<0>(EpilogueTile{}), cute::size<1>(EpilogueTile{}), + cute::Int{}), + cute::conditional_t, + cute::Step>{})); + + constexpr static bool support_smem_reuse = + is_source_supported && is_destination_supported && StagesD <= StagesC + && cute::cosize(cute::take<0, 2>(SmemLayoutC{})) + == cute::cosize(cute::take<0, 2>(SmemLayoutD{})); + static_assert(not(ReuseSmemC && not support_smem_reuse), "Smem reuse requirements not met"); + + constexpr static size_t SmemAlignmentD = cutlass::detail::alignment_for_swizzle(SmemLayoutD{}); + constexpr static size_t SmemAlignmentC = cutlass::detail::alignment_for_swizzle(SmemLayoutC{}); + constexpr static size_t MaxSmemAlignment = cute::max(SmemAlignmentC, SmemAlignmentD); + + using SmemArrayTypeC = cute::ArrayEngine>; + using SmemArrayTypeD = cute::ArrayEngine>; + + using EmptyType = cute::tuple<>; + using SmemCStorage = + cute::conditional_t; + using SmemDStorage = cute::conditional_t; + + struct CollectiveStorageWithC { + alignas(SmemAlignmentC) cute::ArrayEngine> smem_C; + alignas(SmemAlignmentD) cute::ArrayEngine> smem_D; + }; + + union CollectiveStorageWithoutC { + cute::array smem_C; + alignas(SmemAlignmentD) cute::ArrayEngine> smem_D; + }; + + union CollectiveStorageReuseC { + alignas(MaxSmemAlignment) cute::ArrayEngine> smem_C; + alignas(MaxSmemAlignment) cute::ArrayEngine> smem_D; + }; + +public: + // TMA pipeline for loading C + using LoadPipeline = cutlass::PipelineTransactionAsync; + using LoadPipelineState = cutlass::PipelineState; + constexpr static uint32_t TmaTransactionBytes = + (cute::size(cute::take<0, 2>(SmemLayoutC{})) + * static_cast(cutlass::sizeof_bits::value)) + / 8; + constexpr static bool RequiresTransactionBytes = true; + + // TMA pipeline for storing D + using StorePipeline = + cute::conditional_t, + cutlass::PipelineTmaStore>; + using StorePipelineState = cutlass::PipelineState; + + struct SharedStorage { + struct TensorStorage { + using CollectiveStorage = + cute::conditional_t>; + CollectiveStorage collective; + + using FusionStorage = typename FusionCallbacks::SharedStorage; + FusionStorage thread0; + FusionStorage thread1; + FusionStorage thread2; + FusionStorage thread3; + } tensors; + + using PipelineStorage = typename LoadPipeline::SharedStorage; + PipelineStorage pipeline; + }; + using TensorStorage = typename SharedStorage::TensorStorage; + using PipelineStorage = typename SharedStorage::PipelineStorage; + + // Host side epilogue arguments + struct Arguments { + typename FusionCallbacks::Arguments thread0{}; + typename FusionCallbacks::Arguments thread1{}; + typename FusionCallbacks::Arguments thread2{}; + typename FusionCallbacks::Arguments thread3{}; + ElementC const* ptr_C; + StrideC dC; + ElementD const* ptr_D; + StrideD dD; + }; + + // Device side epilogue params + struct Params { + using TMA_C = decltype(cute::make_tma_copy( + CopyOpG2S{}, + cute::make_tensor(cute::make_gmem_ptr(nullptr), + cute::repeat_like(StrideC{}, int32_t(0)), StrideC{}), + cute::take<0, 2>(SmemLayoutC{}), EpilogueTile{}, cute::_1{})); + using TMA_D = decltype(cute::make_tma_copy( + CopyOpS2G{}, + cute::make_tensor(cute::make_gmem_ptr(nullptr), + cute::repeat_like(StrideD{}, int32_t(0)), StrideD{}), + cute::take<0, 2>(SmemLayoutD{}), EpilogueTile{}, cute::_1{})); + + typename FusionCallbacks::Params thread0{}; + typename FusionCallbacks::Params thread1{}; + typename FusionCallbacks::Params thread2{}; + typename FusionCallbacks::Params thread3{}; + TMA_C tma_load_c; + TMA_D tma_store_d; + uint32_t tma_transaction_bytes = TmaTransactionBytes; + }; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + QuadCollectiveEpilogue(Params const& params_, TensorStorage& shared_tensors) + : params(params_) + , fusion_callbacks0(params_.thread0, shared_tensors.thread0) + , fusion_callbacks1(params_.thread1, shared_tensors.thread1) + , fusion_callbacks2(params_.thread2, shared_tensors.thread2) + , fusion_callbacks3(params_.thread3, shared_tensors.thread3) + { + } + + template + static bool can_implement(ProblemShape const& problem_shape, [[maybe_unused]] Arguments const& args) + { + auto problem_shape_MNKL = cute::append<4>(problem_shape, 1); + auto [M, N, K, L] = problem_shape_MNKL; + auto shape = cute::make_shape(M, N, L); + + bool implementable = true; + if constexpr (is_destination_supported) { + constexpr int tma_alignment_bits_D = + cutlass::detail::get_output_alignment_bits(); + constexpr int min_tma_aligned_elements_D = + tma_alignment_bits_D / cutlass::sizeof_bits::value; + if constexpr (cute::is_same_v) { // ignore L stride for implicit gemm + implementable = cutlass::detail::check_alignment( + cute::take<0, 2>(shape), cute::take<0, 2>(StrideD{})); + } else { + implementable = + cutlass::detail::check_alignment(shape, StrideD{}); + } + } + + if constexpr (not cute::is_void_v) { + constexpr int tma_alignment_bits_C = cutlass::detail::get_input_alignment_bits(); + constexpr int min_tma_aligned_elements_C = + tma_alignment_bits_C / cutlass::sizeof_bits::value; + if constexpr (cute::is_same_v) { // ignore L stride for implicit gemm + implementable = implementable + && cutlass::detail::check_alignment( + cute::take<0, 2>(shape), cute::take<0, 2>(StrideC{})); + } else { + implementable = + implementable + && cutlass::detail::check_alignment(shape, StrideC{}); + } + } + + if (!implementable) { + CUTLASS_TRACE_HOST( + " CAN IMPLEMENT: Problem Size doesn't meet the minimum alignment requirements for " + "TMA.\n"); + } + + bool fusion_implementable = true; + ; + fusion_implementable = + fusion_implementable && FusionCallbacks::can_implement(problem_shape, args.thread0); + fusion_implementable = + fusion_implementable && FusionCallbacks::can_implement(problem_shape, args.thread1); + fusion_implementable = + fusion_implementable && FusionCallbacks::can_implement(problem_shape, args.thread2); + fusion_implementable = + fusion_implementable && FusionCallbacks::can_implement(problem_shape, args.thread3); + + if (!fusion_implementable) { + CUTLASS_TRACE_HOST( + " CAN IMPLEMENT: Problem Size doesn't meet the minimum requirements for " + "FusionCallbacks.\n"); + } + + return implementable && fusion_implementable; + } + + template + CUTLASS_HOST_DEVICE static constexpr int get_load_pipe_increment(TileShapeMNK tile_shape_MNK) + { + // Compute number of epilogue subtiles + return cute::size<1>( + zipped_divide(cute::make_layout(cute::take<0, 2>(tile_shape_MNK)), EpilogueTile{})); + } + + template + CUTLASS_HOST_DEVICE static constexpr int get_store_pipe_increment(TileShapeMNK tile_shape_MNK) + { + return get_load_pipe_increment(tile_shape_MNK); + } + + template + static size_t get_workspace_size(ProblemShape const& problem_shape, Arguments const& args) + { + return 0; + } + + template + static cutlass::Status initialize_workspace(ProblemShape const& problem_shape, Arguments const& args, + void* workspace, cudaStream_t stream, + cutlass::CudaHostAdapter* cuda_adapter = nullptr) + { + return cutlass::Status::kSuccess; + } + + CUTLASS_DEVICE + bool is_producer_load_needed() const { return fusion_callbacks0.is_producer_load_needed(); } + + template + CUTLASS_DEVICE auto load(LoadPipeline load_pipeline, LoadPipelineState load_pipe_producer_state, + ProblemShapeMNKL problem_shape_mnkl, TileShapeMNK tile_shape_MNK, + TileCoordMNKL tile_coord_mnkl, TiledMma tiled_mma, int thread_idx, + TensorStorage& shared_tensors, int subtile_idx = -1) + { + // Indexing variables + auto [M, N, K, L] = problem_shape_mnkl; + auto [m_coord, n_coord, k_coord, l_coord] = tile_coord_mnkl; + + // The tma tensor C under im2col mode only has two modes (M, N) which + // should be local tiled with only (m_coord, n_coord). + auto coord_shape = cute::conditional_return( + cute::make_coord(m_coord, n_coord), cute::make_coord(m_coord, n_coord, l_coord)); + + // Represent the full source tensor, slice to get the tile this CTA is currently responsible for + cute::Tensor mC_mn = params.tma_load_c.get_tma_tensor(cute::make_shape(M, N, L)); // (M,N,L) + cute::Tensor mC = cute::coalesce(mC_mn, cute::take<0, 2>(CtaTileMNK{})); + cute::Tensor gC = + cute::local_tile(mC, cute::take<0, 2>(CtaTileMNK{}), coord_shape); // (CTA_M,CTA_N) + + // Apply epilogue subtile, get matching smem tensor + auto ptr_sC = shared_tensors.collective.smem_C.begin(); + cute::Tensor gC_epi = cute::flat_divide(gC, EpilogueTile{}); // (EPI_TILE_M,EPI_TILE_N,EPI_M,EPI_N) + cute::Tensor sC_epi = cute::make_tensor(cute::make_smem_ptr(ptr_sC), + SmemLayoutC{}); // (EPI_TILE_M,EPI_TILE_N,PIPE_C) + + // Prepare the thread(b)lock's (G)mem to (S)mem TMA tiled copy (bGS_) + cute::ThrCopy thrblk_g2s = params.tma_load_c.get_slice(cute::_0{}); + cute::Tensor bGS_gC = thrblk_g2s.partition_S(gC_epi); // (G2S,G2S_M,G2S_N,EPI_M,EPI_N) + cute::Tensor bGS_sC = thrblk_g2s.partition_D(sC_epi); // (G2S,G2S_M,G2S_N,PIPE_C) + + // Get the fusion callbacks for the producer load warp + auto pld_args = cutlass::epilogue::fusion::detail::ProducerLoadArgs( + problem_shape_mnkl, CtaTileMNK{}, tile_coord_mnkl, tiled_mma, EpilogueTile{}, thread_idx); + auto pld_callbacks = fusion_callbacks0.get_producer_load_callbacks(pld_args); + bool is_C_load_needed = is_source_supported && fusion_callbacks0.is_C_load_needed(); + + // Predication for TMA load (one thread issues TMA load) + bool issue_tma_load = cute::elect_one_sync(); + + // Pre-loop fusion callback entry point + pld_callbacks.begin(); + + CUTLASS_PRAGMA_UNROLL + for (int epi_n = 0; epi_n < cute::size<3>(gC_epi); ++epi_n) { + CUTLASS_PRAGMA_UNROLL + for (int epi_m = 0; epi_m < cute::size<2>(gC_epi); ++epi_m) { + if (subtile_idx != -1 + && (epi_n * static_cast(cute::size<2>(gC_epi)) + epi_m) != subtile_idx) { + continue; + } + // Acquire the lock for this stage + constexpr uint16_t mcast_mask = 0; + uint64_t* tma_barrier = load_pipeline.producer_get_barrier(load_pipe_producer_state); + load_pipeline.producer_acquire(load_pipe_producer_state); + + // Loop fusion callback entry point + pld_callbacks.step(tma_barrier, epi_m, epi_n, load_pipe_producer_state.count(), + issue_tma_load); + + // Execute the TMA load for C if needed + if (issue_tma_load && is_C_load_needed) { + cute::copy(params.tma_load_c.with(*tma_barrier, mcast_mask), + bGS_gC(cute::_, cute::_, cute::_, epi_m, epi_n), + bGS_sC(cute::_, cute::_, cute::_, load_pipe_producer_state.index())); + load_pipeline.producer_expect_transaction(load_pipe_producer_state); + } + + // Commit TMA loads for this stage and release the lock + load_pipeline.producer_commit(load_pipe_producer_state); + ++load_pipe_producer_state; + } + } + + // Post-loop fusion callback entry point + pld_callbacks.end(); + + return load_pipe_producer_state; + } + + CUTLASS_DEVICE auto load_tail(LoadPipeline load_pipeline, LoadPipelineState load_pipe_producer_state) + { + bool issue_tma_load = cute::elect_one_sync(); + if (issue_tma_load) { + load_pipeline.producer_tail(load_pipe_producer_state); + } + + return load_pipe_producer_state; + } + + template + CUTLASS_DEVICE auto + store(LoadPipeline load_pipeline, LoadPipelineState load_pipe_consumer_state, + StorePipeline store_pipeline, StorePipelineState store_pipe_producer_state, + ProblemShapeMNKL problem_shape_mnkl, TileShapeMNK tile_shape_MNK, + TileCoordMNKL tile_coord_mnkl, cute::Tensor accumulators0, + cute::Tensor accumulators1, + cute::Tensor accumulators2, + cute::Tensor accumulators3, TiledMma tiled_mma, int thread_idx, + TensorStorage& shared_tensors, int subtile_idx = -1) + { + using ElementAccumulator = typename AccEngine::value_type; + using ElementCompute_ = + typename cutlass::epilogue::fusion::FusionCallbacksTraits::ElementCompute; + using ElementCompute = + cute::conditional_t, ElementAccumulator, ElementCompute_>; + + static_assert(cute::is_rmem::value, "Accumulator must be RF resident."); + static_assert(cute::rank(AccLayout{}) == 3, + "Accumulator must be MMA-partitioned: (MMA,MMA_M,MMA_N)"); + static_assert(cute::rank(ProblemShapeMNKL{}) == 4, "ProblemShapeMNKL must be rank 4"); + static_assert(cute::is_static::value, "TileShapeMNK must be static"); + static_assert(cute::rank(TileShapeMNK{}) == 3, "TileShapeMNK must be rank 3"); + static_assert(cute::rank(TileCoordMNKL{}) == 4, "TileCoordMNKL must be rank 4"); + + // Indexing variables + auto [M, N, K, L] = problem_shape_mnkl; + auto [m_coord, n_coord, k_coord, l_coord] = tile_coord_mnkl; + + // The tma tensor D under im2col mode only has two modes (M, N) which + // should be local tiled with only (m_coord, n_coord). + auto coord_shape = cute::conditional_return( + cute::make_coord(m_coord, n_coord), cute::make_coord(m_coord, n_coord, l_coord)); + + // Represent the full output tensor, slice to get the tile this CTA is responsible for + cute::Tensor mD_mn = params.tma_store_d.get_tma_tensor(cute::make_shape(M, N, L)); // (M,N,L) + cute::Tensor mD = cute::coalesce(mD_mn, cute::take<0, 2>(CtaTileMNK{})); + cute::Tensor gD = + cute::local_tile(mD, cute::take<0, 2>(CtaTileMNK{}), coord_shape); // (CTA_M,CTA_N) + + // Apply epilogue subtiling + cute::Tensor gD_epi = cute::flat_divide(gD, EpilogueTile{}); // (EPI_TILE_M,EPI_TILE_N,EPI_M,EPI_N) + + // Construct the corresponding pipelined smem tensors + auto ptr_sC = shared_tensors.collective.smem_C.begin(); + auto ptr_sD = shared_tensors.collective.smem_D.begin(); + cute::Tensor sC_epi = cute::as_position_independent_swizzle_tensor(cute::make_tensor( + cute::make_smem_ptr(ptr_sC), SmemLayoutC{})); // (EPI_TILE_M,EPI_TILE_N,PIPE_C) + cute::Tensor sD_epi = cute::as_position_independent_swizzle_tensor(cute::make_tensor( + cute::make_smem_ptr(ptr_sD), SmemLayoutD{})); // (EPI_TILE_M,EPI_TILE_N,PIPE_D) + + cute::TiledCopy tiled_copy_C_atom = cute::make_tiled_copy_C_atom(CopyAtomC{}, tiled_mma); + + // (t)hread-partition for (r)egister to (r)egister copy (tRR_) + cute::TiledCopy tiled_r2r = [&]() CUTLASS_LAMBDA_FUNC_INLINE { + if constexpr (IsUseR2R) { + return cute::make_tiled_copy_S(cute::Copy_Atom{}, + tiled_copy_C_atom); + } else { + return cute::make_tiled_copy_S( + cute::Copy_Atom, ElementCompute>{}, + tiled_copy_C_atom); + } + }(); + cute::ThrCopy thread_r2r = tiled_r2r.get_slice(thread_idx); + + // (t)hread-partition for (r)egister to (s)mem copy (tRS_) + cute::TiledCopy tiled_r2s = [&]() CUTLASS_LAMBDA_FUNC_INLINE { + if constexpr (IsUseR2R) { + return cute::make_tiled_copy_D(cute::Copy_Atom{}, tiled_r2r); + } else { + return cute::make_tiled_copy_S(cute::Copy_Atom{}, + tiled_copy_C_atom); + } + }(); + cute::ThrCopy thread_r2s = tiled_r2s.get_slice(thread_idx); + cute::Tensor tRS_rAcc0 = thread_r2s.retile_S(accumulators0); // ((R2S,R2S_V),MMA_M,MMA_N) + cute::Tensor tRS_rAcc1 = thread_r2s.retile_S(accumulators1); // ((R2S,R2S_V),MMA_M,MMA_N) + cute::Tensor tRS_rAcc2 = thread_r2s.retile_S(accumulators2); // ((R2S,R2S_V),MMA_M,MMA_N) + cute::Tensor tRS_rAcc3 = thread_r2s.retile_S(accumulators3); // ((R2S,R2S_V),MMA_M,MMA_N) + + cute::Tensor tRS_sD = thread_r2s.partition_D(sD_epi); // (R2S,R2S_M,R2S_N,PIPE_D) + + auto mma_tile_m = cute::size<0>(TileShapeMNK{}) / cute::size<1>(tRS_rAcc0); + auto mma_tile_n = cute::size<1>(TileShapeMNK{}) / cute::size<2>(tRS_rAcc0); + auto epi_tile_m = cute::size<0>(EpilogueTile{}); + auto epi_tile_n = cute::size<1>(EpilogueTile{}); + + // Allocate D registers + cute::Layout tRS_rD_layout = + cute::make_layout(cute::take<0, 3>(cute::shape(thread_r2s.partition_S(sD_epi)))); + cute::Tensor tRS_rD = cute::make_tensor(tRS_rD_layout); // (R2S,R2S_M,R2S_N) + + // Vectorized fragment view + constexpr int FragmentSize = DispatchPolicy::FragmentSize; + cute::Tensor tRS_rAcc_frg0 = + cute::recast>(tRS_rAcc0); + cute::Tensor tRS_rAcc_frg1 = + cute::recast>(tRS_rAcc1); + cute::Tensor tRS_rAcc_frg2 = + cute::recast>(tRS_rAcc2); + cute::Tensor tRS_rAcc_frg3 = + cute::recast>(tRS_rAcc3); + + cute::Tensor tRS_rD_frg = cute::recast>(tRS_rD); + CUTE_STATIC_ASSERT(cute::size<0>(tRS_rAcc0) % FragmentSize == 0, + "Fragment size does not vectorize properly"); + + // (t)hread-partition for (s)mem to (r)egister copy (tSR_) + cute::TiledCopy tiled_s2r = + cute::make_tiled_copy_S(cute::Copy_Atom{}, tiled_copy_C_atom); + cute::ThrCopy thread_s2r = tiled_s2r.get_slice(thread_idx); + cute::Tensor tSR_sC = thread_s2r.partition_S(sC_epi); // (S2R,S2R_M,S2R_N,PIPE_C) + cute::Layout tSR_rC_layout = thread_s2r.retile_D(tRS_rD).layout(); // (S2R,S2R_M,S2R_N) + + // Allocate C registers + // If C smem load is a non-vectorized dst(i) = src(i) then we can allocate C registers directly in the compute type + // to eliminate some redundant pack+unpack instruction sequences for sub-word types + constexpr bool IsDirectS2R = + cute::is_same_v> + && decltype(cute::max_common_vector(tSR_rC_layout, tSR_sC.layout()))::value <= 1; + using RegisterElementC = cute::conditional_t; + cute::Tensor tRS_rC = cute::make_tensor(tRS_rD_layout); // (R2S,R2S_M,R2S_N) + cute::Tensor tSR_rC = thread_s2r.retile_D(tRS_rC); // (S2R,S2R_M,S2R_N) + + // thread(b)lock-partition for (s)mem to (g)mem copy (bSG_) + cute::ThrCopy thrblk_s2g = params.tma_store_d.get_slice(cute::_0{}); + cute::Tensor bSG_sD = thrblk_s2g.partition_S(sD_epi); // (S2G,S2G_M,S2G_N,PIPE_D) + cute::Tensor bSG_gD = thrblk_s2g.partition_D(gD_epi); // (S2G,S2G_M,S2G_N,EPI_M,EPI_N) + + // OOB predication for tile quantization "residue" + // Absolute coordinate tensors (dynamic) + cute::Tensor mD_crd = cute::make_identity_tensor(cute::make_shape(M, N)); // (M,N) + cute::Tensor cD_mn = cute::local_tile(mD_crd, cute::take<0, 2>(CtaTileMNK{}), + cute::make_coord(m_coord, n_coord)); // (CTA_M,CTA_N) + cute::Tensor tRS_cD_mn = [&]() CUTLASS_LAMBDA_FUNC_INLINE { + if constexpr (IsUseR2R) { + // (t)hread-partition for ConsumerStoreCallbacks. + cute::TiledCopy tiled_cst = cute::make_tiled_copy_S( + cute::Copy_Atom{}, tiled_copy_C_atom); + cute::ThrCopy thread_cst = tiled_cst.get_slice(thread_idx); + return thread_cst.partition_S( + cute::flat_divide(cD_mn, EpilogueTile{})); // (R2S,R2S_M,R2S_N,EPI_M,EPI_N) + } else { + return thread_r2s.partition_S( + cute::flat_divide(cD_mn, EpilogueTile{})); // (R2S,R2S_M,R2S_N,EPI_M,EPI_N) + } + }(); + // Relative coordinate tensors (static) + cute::Tensor cD = cute::make_coord_tensor(cD_mn.layout()); // (CTA_M,CTA_N) + cute::Tensor tRS_cD = cute::make_coord_tensor(tRS_cD_mn.layout()); // (R2S,R2S_M,R2S_N,EPI_M,EPI_N) + // Subtract the global "bottom right" corner from the local "top left" corner to get the max relative coordinate + auto residue_cD = cute::make_coord(M, N) - cD_mn(cute::_0{}); // (m,n) + auto residue_tRS_cD = cute::make_coord(M, N) - tRS_cD_mn(cute::_0{}); // (m,n) + + CUTE_STATIC_ASSERT(epi_tile_m % mma_tile_m == 0, "MMA_TILE_M must divide EPI_TILE_M"); + + if constexpr (epi_tile_m * epi_tile_n > mma_tile_m * mma_tile_n) { + // When the epilogue subtile is larger than the MMA tiles, loop over multiple MMA tiles + CUTE_STATIC_ASSERT(epi_tile_n % mma_tile_n == 0, "MMA_TILE_N must divide EPI_TILE_N"); + } else { + CUTE_STATIC_ASSERT(mma_tile_n % epi_tile_n == 0, "EPI_TILE_N must divide MMA_TILE_N"); + } + + // Get cute::TiledCopy for partition reference when consumer store. + cute::TiledCopy tiled_copy_partition_ref = + cute::make_tiled_copy_S(cute::Copy_Atom{}, tiled_copy_C_atom); + // Get the fusion callbacks for the consumer store warps + constexpr bool RefSrc = true; // Register tensors reference tiled copy src layout + auto cst_args = cutlass::epilogue::fusion::detail::ConsumerStoreArgs( + problem_shape_mnkl, CtaTileMNK{}, tile_coord_mnkl, tiled_mma, EpilogueTile{}, + tiled_copy_partition_ref, cD, residue_cD, tRS_cD, residue_tRS_cD, tRS_rC, thread_idx); + auto cst_callbacks0 = fusion_callbacks0.template get_consumer_store_callbacks(cst_args); + auto cst_callbacks1 = fusion_callbacks1.template get_consumer_store_callbacks(cst_args); + auto cst_callbacks2 = fusion_callbacks2.template get_consumer_store_callbacks(cst_args); + auto cst_callbacks3 = fusion_callbacks3.template get_consumer_store_callbacks(cst_args); + bool is_producer_load_needed = fusion_callbacks0.is_producer_load_needed(); + bool is_C_load_needed = is_source_supported && fusion_callbacks0.is_C_load_needed(); + + using FragmentVisit = decltype(cst_callbacks0.visit(tRS_rAcc_frg0(0), 0, 0, 0)); + constexpr bool IsDirectR2S = + cute::is_same_v>; + using RegisterElementD = cute::conditional_t; + cute::Tensor tRS_rCompute = cute::make_tensor(tRS_rD_layout); // (R2S,R2S_M,R2S_N) + cute::Tensor tRS_rCompute_frg = + cute::recast>(tRS_rCompute); + + // Thread synchronizer for previously issued waits or fences + // to ensure visibility of smem reads/writes to threads or TMA unit + auto synchronize = [&]() CUTLASS_LAMBDA_FUNC_INLINE { + cutlass::arch::NamedBarrier::sync(size(TiledMma{}), + cutlass::arch::ReservedNamedBarriers::EpilogueBarrier); + }; + + // Predication for TMA store (one warp issues TMA store) + bool issue_tma_store = (thread_idx / cutlass::NumThreadsPerWarp) == 0; + + // In the reuse smem configuration we have StagesC smem buffers and at most StagesD + // committed TMA stores in flight. The TMA store pipeline producer acquire returns when at + // most StagesD-1 committed stores are in-flight, so we can only guarantee store completion + // after StagesD iterations, then we can begin issuing releases on the smem buffer locks. + // store_pipe_producer_state tracks the acquire and load_pipe_consumer_state tracks the + // release, in circular buffer fashion. + LoadPipelineState load_wait_state = load_pipe_consumer_state; + if constexpr (ReuseSmemC) { + load_wait_state = store_pipe_producer_state; + load_wait_state.phase_ ^= 1; + } + + // We can delay issue of TMA store by one iteration to achieve better interleaving of non-TMA instructions + // Sync requirements of smem reuse may preclude this optimization + // Delayed stores cause delayed stage releases which causes deadlock when StagesC == StagesD + [[maybe_unused]] int epi_m_prev = 0; + [[maybe_unused]] int epi_n_prev = 0; + static_assert(not(DelayTmaStore and ReuseSmemC and StagesC <= StagesD), + "This TMA epilogue configuration will deadlock"); + + // The TMA store sequence for one subtile iteration + auto tma_store_fn = [&](int epi_m, int epi_n) CUTLASS_LAMBDA_FUNC_INLINE { + // Write the tile from smem to gmem with TMA + cutlass::arch::fence_view_async_shared(); // ensure smem writes are visible to TMA + synchronize(); // ensure all threads have issued their async fence + if constexpr (is_destination_supported) { + if (issue_tma_store) { + cute::copy(params.tma_store_d, + bSG_sD(cute::_, cute::_, cute::_, store_pipe_producer_state.index()), + bSG_gD(cute::_, cute::_, cute::_, epi_m, epi_n)); + } + } + + // Post async fence, pre TMA commit callback entry point + cst_callbacks0.tma_store(epi_m, epi_n, store_pipe_producer_state.count(), issue_tma_store); + cst_callbacks1.tma_store(epi_m, epi_n, store_pipe_producer_state.count(), issue_tma_store); + cst_callbacks2.tma_store(epi_m, epi_n, store_pipe_producer_state.count(), issue_tma_store); + cst_callbacks3.tma_store(epi_m, epi_n, store_pipe_producer_state.count(), issue_tma_store); + + // Commit the TMA stores for this stage + if (issue_tma_store) { + store_pipeline.producer_commit(store_pipe_producer_state); + } + ++store_pipe_producer_state; + ++issued_stores; + + // Wait for the next smem buffer to be available + if (issue_tma_store) { + store_pipeline.producer_acquire(store_pipe_producer_state); + } + synchronize(); + + if constexpr (ReuseSmemC) { + // producer_acquire returns when at most StagesD-1 committed stores are pending + bool store_finished = issued_stores > StorePipeline::UnacquiredStages; + // Let dma warp know earliest smem buffer is consumed and empty after StagesD producer commits + if (store_finished) { + if (is_producer_load_needed) { + load_pipeline.consumer_release(load_pipe_consumer_state); + } + ++load_pipe_consumer_state; + } + } + }; + + // + // BEGIN EPILOGUE + // + + // Pre-loop fusion callback entry point + cst_callbacks0.begin(); + cst_callbacks1.begin(); + cst_callbacks2.begin(); + cst_callbacks3.begin(); + + if (cst_callbacks0.begin_sync_needed()) { + synchronize(); + } + + // For each output tile + CUTLASS_PRAGMA_UNROLL + for (int epi_n = 0; epi_n < cute::size<3>(gD_epi); ++epi_n) { + CUTLASS_PRAGMA_UNROLL + for (int epi_m = 0; epi_m < cute::size<2>(gD_epi); ++epi_m) { + [[maybe_unused]] bool is_first_iteration = epi_m == 0 && epi_n == 0; + bool is_last_iteration = + epi_m == cute::size<2>(gD_epi) - 1 && epi_n == cute::size<3>(gD_epi) - 1; + + if (subtile_idx != -1 + && (epi_n * static_cast(cute::size<2>(gD_epi)) + epi_m) != subtile_idx) { + continue; + } + + cst_callbacks0.begin_loop(epi_m, epi_n); + cst_callbacks1.begin_loop(epi_m, epi_n); + cst_callbacks2.begin_loop(epi_m, epi_n); + cst_callbacks3.begin_loop(epi_m, epi_n); + + if (is_producer_load_needed) { + // Wait for the producer load to fill smem + load_pipeline.consumer_wait(load_wait_state); + + if (is_C_load_needed) { + // Copy source tile from smem to register + cute::copy(tiled_s2r, + tSR_sC(cute::_, cute::_, cute::_, load_wait_state.index()), tSR_rC); + // Ensure smem loads are complete before reusing smem for mixed types/layouts + if constexpr (ReuseSmemC && not(SmemLayoutC{} == SmemLayoutD{})) { + synchronize(); + } + } + } + + // First loop fusion callback entry point + cst_callbacks0.previsit(epi_m, epi_n, load_wait_state.count(), is_producer_load_needed); + cst_callbacks1.previsit(epi_m, epi_n, load_wait_state.count(), is_producer_load_needed); + cst_callbacks2.previsit(epi_m, epi_n, load_wait_state.count(), is_producer_load_needed); + cst_callbacks3.previsit(epi_m, epi_n, load_wait_state.count(), is_producer_load_needed); + + if (is_producer_load_needed) { + if constexpr (not ReuseSmemC) { + // Let producer load warp know smem buffers are consumed and empty + cutlass::arch::fence_view_async_shared(); + load_pipeline.consumer_release(load_pipe_consumer_state); + ++load_pipe_consumer_state; + } + ++load_wait_state; + } + + if constexpr (epi_tile_m * epi_tile_n > mma_tile_m * mma_tile_n) { + // When the epilogue subtile is larger than the MMA tiles, loop over multiple + // MMA tiles + static constexpr int MmaMPerEpiM = epi_tile_m / mma_tile_m; + static constexpr int MmaNPerEpiN = epi_tile_n / mma_tile_n; + + CUTLASS_PRAGMA_UNROLL + for (int mma_n_in_epi = 0; mma_n_in_epi < MmaNPerEpiN; ++mma_n_in_epi) { + int mma_n = (epi_n * MmaNPerEpiN) + mma_n_in_epi; + + CUTLASS_PRAGMA_UNROLL + for (int mma_m_in_epi = 0; mma_m_in_epi < MmaMPerEpiM; ++mma_m_in_epi) { + int mma_m = (epi_m * MmaMPerEpiM) + mma_m_in_epi; + cute::Tensor tRS_rAcc_frg_mn0 = tRS_rAcc_frg0(cute::_, mma_m, mma_n); + cute::Tensor tRS_rAcc_frg_mn1 = tRS_rAcc_frg1(cute::_, mma_m, mma_n); + cute::Tensor tRS_rAcc_frg_mn2 = tRS_rAcc_frg2(cute::_, mma_m, mma_n); + cute::Tensor tRS_rAcc_frg_mn3 = tRS_rAcc_frg3(cute::_, mma_m, mma_n); + + int idx_in_epi_subtile = (mma_n_in_epi * MmaMPerEpiM + mma_m_in_epi); + + auto comp0 = cst_callbacks0.visit(tRS_rAcc_frg_mn0(0), + idx_in_epi_subtile, epi_m, epi_n); + auto comp1 = cst_callbacks1.visit(tRS_rAcc_frg_mn1(0), + idx_in_epi_subtile, epi_m, epi_n); + auto comp2 = cst_callbacks2.visit(tRS_rAcc_frg_mn2(0), + idx_in_epi_subtile, epi_m, epi_n); + auto comp3 = cst_callbacks3.visit(tRS_rAcc_frg_mn3(0), + idx_in_epi_subtile, epi_m, epi_n); + QuadAddOp> quad_add_op; + auto combined_comp = quad_add_op(comp0, comp1, comp2, comp3); + tRS_rCompute_frg(idx_in_epi_subtile) = combined_comp; + } + } + } else { + int mma_m = epi_m; + int mma_n = (epi_n * cute::size<1>(EpilogueTile{})) / mma_tile_n; + cute::Tensor tRS_rAcc_frg_mn0 = tRS_rAcc_frg0(cute::_, mma_m, mma_n); + cute::Tensor tRS_rAcc_frg_mn1 = tRS_rAcc_frg1(cute::_, mma_m, mma_n); + cute::Tensor tRS_rAcc_frg_mn2 = tRS_rAcc_frg2(cute::_, mma_m, mma_n); + cute::Tensor tRS_rAcc_frg_mn3 = tRS_rAcc_frg3(cute::_, mma_m, mma_n); + + // Vectorized fragment loop with visitor callback entry point + int epi_n_in_mma = epi_n % (mma_tile_n / epi_tile_n); + int r2s_v = epi_n_in_mma * size(tRS_rCompute_frg); + CUTLASS_PRAGMA_UNROLL + for (int epi_v = 0; epi_v < size(tRS_rCompute_frg); ++epi_v) { + auto comp0 = cst_callbacks0.visit(tRS_rAcc_frg_mn0(r2s_v + epi_v), epi_v, + epi_m, epi_n); + auto comp1 = cst_callbacks1.visit(tRS_rAcc_frg_mn1(r2s_v + epi_v), epi_v, + epi_m, epi_n); + auto comp2 = cst_callbacks2.visit(tRS_rAcc_frg_mn2(r2s_v + epi_v), epi_v, + epi_m, epi_n); + auto comp3 = cst_callbacks3.visit(tRS_rAcc_frg_mn3(r2s_v + epi_v), epi_v, + epi_m, epi_n); + QuadAddOp> quad_add_op; + auto combined_comp = quad_add_op(comp0, comp1, comp2, comp3); + tRS_rCompute_frg(epi_v) = combined_comp; + } + } + + // The latest we can delay the TMA store is right before the smem store of the next iteration + // since the current TMA store needs to be committed before we can acquire the next smem buffer + if constexpr (DelayTmaStore) { + // Issue TMA stores for the previous subtile + if (not is_first_iteration and subtile_idx == -1) { + tma_store_fn(epi_m_prev, epi_n_prev); + } + epi_m_prev = epi_m; + epi_n_prev = epi_n; + } + + // Smem reduction callback entry point using current store buffer for workspace + cst_callbacks0.reduce(sD_epi(cute::_, cute::_, store_pipe_producer_state.index()), + synchronize, epi_m, epi_n, is_last_iteration, tRS_rCompute_frg); + cst_callbacks1.reduce(sD_epi(cute::_, cute::_, store_pipe_producer_state.index()), + synchronize, epi_m, epi_n, is_last_iteration, tRS_rCompute_frg); + cst_callbacks2.reduce(sD_epi(cute::_, cute::_, store_pipe_producer_state.index()), + synchronize, epi_m, epi_n, is_last_iteration, tRS_rCompute_frg); + cst_callbacks3.reduce(sD_epi(cute::_, cute::_, store_pipe_producer_state.index()), + synchronize, epi_m, epi_n, is_last_iteration, tRS_rCompute_frg); + + // Copy tile from register to regiser if needed + if constexpr (IsUseR2R) { + // retile source and destination for tiled_r2r + cute::Tensor tRR_rD_src = + thread_r2r.retile_S(tRS_rCompute); // (R2R,R2R_M,R2R_N,EPI_M,EPI_N) + cute::Tensor tRR_rD_dst = + thread_r2r.retile_D(tRS_rCompute); // (R2R,R2R_M,R2R_N,EPI_M,EPI_N) + + // Output register transformation before copying to shared memory. + cute::copy(tiled_r2r, tRR_rD_src, tRR_rD_dst); + } + + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < size(tRS_rD_frg); ++i) { + tRS_rD_frg(i) = + cutlass::NumericArrayConverter{}( + tRS_rCompute_frg(i)); + } + + // Copy tile from register to smem + if constexpr (is_destination_supported) { + cute::copy(tiled_r2s, tRS_rD, + tRS_sD(cute::_, cute::_, cute::_, store_pipe_producer_state.index())); + } + + // Post reduction, pre TMA store callback entry point + constexpr bool issue_smem_store = true; // No smem store predication + cst_callbacks0.postreduce(epi_m, epi_n, store_pipe_producer_state.count(), + issue_smem_store); + cst_callbacks1.postreduce(epi_m, epi_n, store_pipe_producer_state.count(), + issue_smem_store); + cst_callbacks2.postreduce(epi_m, epi_n, store_pipe_producer_state.count(), + issue_smem_store); + cst_callbacks3.postreduce(epi_m, epi_n, store_pipe_producer_state.count(), + issue_smem_store); + + if constexpr (not DelayTmaStore) { + // Issue TMA stores for this subtile + tma_store_fn(epi_m, epi_n); + } + + cst_callbacks0.end_loop(epi_m, epi_n); + cst_callbacks1.end_loop(epi_m, epi_n); + cst_callbacks2.end_loop(epi_m, epi_n); + cst_callbacks3.end_loop(epi_m, epi_n); + } // for epi_m + } // for epi_n + + if constexpr (DelayTmaStore) { + // Issue TMA stores for the last subtile + tma_store_fn(epi_m_prev, epi_n_prev); + } + + // Post-loop fusion callback entry point + cst_callbacks0.end(); + cst_callbacks1.end(); + cst_callbacks2.end(); + cst_callbacks3.end(); + + return cute::make_tuple(load_pipe_consumer_state, store_pipe_producer_state); + } + + CUTLASS_DEVICE auto store_tail(LoadPipeline load_pipeline, + LoadPipelineState load_pipe_consumer_state, + StorePipeline store_pipeline, + StorePipelineState store_pipe_producer_state) + { + // wait for all TMA stores to complete + store_pipeline.producer_tail(store_pipe_producer_state); + // reset store counter + issued_stores = 0; + + if constexpr (ReuseSmemC) { + if (fusion_callbacks0.is_producer_load_needed()) { + // Issue releases on up to StagesD-1 previously issued TMA stores + constexpr int release_stages = + cute::min(StorePipeline::UnacquiredStages, get_load_pipe_increment(CtaTileMNK{})); + CUTLASS_PRAGMA_UNROLL + for (int stage = 0; stage < release_stages; ++stage) { + load_pipeline.consumer_release(load_pipe_consumer_state); + ++load_pipe_consumer_state; + } + } + } + + return cute::make_tuple(load_pipe_consumer_state, store_pipe_producer_state); + } + + /// Issue Tma Descriptor Prefetch -- ideally from a single thread for best performance + CUTLASS_DEVICE + static void prefetch_tma_descriptors(Params const& epilogue_params) + { + if constexpr (is_source_supported) { + cute::prefetch_tma_descriptor(epilogue_params.tma_load_c.get_tma_descriptor()); + } + if constexpr (is_destination_supported) { + cute::prefetch_tma_descriptor(epilogue_params.tma_store_d.get_tma_descriptor()); + } + } + + template + static constexpr Params to_underlying_arguments(ProblemShape const& problem_shape, + Arguments const& args, + [[maybe_unused]] void* workspace) + { + // Optionally append 1s until problem shape is rank-4 in case its is only rank-3 (MNK) + auto problem_shape_MNKL = cute::append<4>(problem_shape, 1); + auto [M, N, K, L] = problem_shape_MNKL; + + uint32_t transaction_bytes = TmaTransactionBytes; + typename Params::TMA_C tma_load_c{}; + if constexpr (is_source_supported) { + cute::Tensor tensor_c = + cute::make_tensor(cute::make_gmem_ptr(args.ptr_C), + cute::make_layout(cute::make_shape(M, N, L), args.dC)); + tma_load_c = cute::make_tma_copy_C_sm90(CopyOpG2S{}, tensor_c, + cute::take<0, 2>(SmemLayoutC{}), EpilogueTile{}); + } + + typename Params::TMA_D tma_store_d{}; + if constexpr (is_destination_supported) { + cute::Tensor tensor_d = + cute::make_tensor(cute::make_gmem_ptr(args.ptr_D), + cute::make_layout(cute::make_shape(M, N, L), args.dD)); + tma_store_d = cute::make_tma_copy_C_sm90(CopyOpS2G{}, tensor_d, + cute::take<0, 2>(SmemLayoutD{}), EpilogueTile{}); + } + + return { FusionCallbacks::to_underlying_arguments(problem_shape, args.thread0, workspace), + FusionCallbacks::to_underlying_arguments(problem_shape, args.thread1, workspace), + FusionCallbacks::to_underlying_arguments(problem_shape, args.thread2, workspace), + FusionCallbacks::to_underlying_arguments(problem_shape, args.thread3, workspace), + tma_load_c, + tma_store_d, + transaction_bytes }; + } + +private: + Params const& params; + FusionCallbacks fusion_callbacks0; + FusionCallbacks fusion_callbacks1; + FusionCallbacks fusion_callbacks2; + FusionCallbacks fusion_callbacks3; + int issued_stores = 0; +}; diff --git a/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_gemm_tma_warpspecialized_cooperative_quad.h b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_gemm_tma_warpspecialized_cooperative_quad.h new file mode 100644 index 0000000..ebcbc36 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_gemm_tma_warpspecialized_cooperative_quad.h @@ -0,0 +1,828 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +#include +#include +// clang-format on + +/** + * These 1 classes/structs are rewritten: + * 1. cutlass::gemm::kernel::GemmUniversal -> QuadGemmUniversal + */ + +// Primary template declaration to enable partial/specialized definitions below. +template +class QuadGemmUniversal; + +// Original file: cutlass/gemm/kernel/sm90_gemm_tma_warpspecialized_cooperative.hpp +// to add multiple accumulators to mma +template +class QuadGemmUniversal< + ProblemShape_, CollectiveMainloop_, CollectiveEpilogue_, TileSchedulerTag_, + cute::enable_if_t>> { +public: + // + // Type Aliases + // + using ProblemShape = ProblemShape_; + static_assert(cute::rank(ProblemShape{}) == 3 or cute::rank(ProblemShape{}) == 4, + "ProblemShape{} should be or "); + + // Mainloop derived types + using CollectiveMainloop = CollectiveMainloop_; + using TileShape = typename CollectiveMainloop::TileShape; + using TiledMma = typename CollectiveMainloop::TiledMma; + using ArchTag = typename CollectiveMainloop::ArchTag; + using ElementA = typename CollectiveMainloop::ElementA; + using StrideA = typename CollectiveMainloop::StrideA; + using ElementB = typename CollectiveMainloop::ElementB; + using StrideB = typename CollectiveMainloop::StrideB; + using DispatchPolicy = typename CollectiveMainloop::DispatchPolicy; + using ElementAccumulator = typename CollectiveMainloop::ElementAccumulator; + using ClusterShape = typename DispatchPolicy::ClusterShape; + using MainloopArguments = typename CollectiveMainloop::Arguments; + using MainloopParams = typename CollectiveMainloop::Params; + // Epilogue derived types + using CollectiveEpilogue = CollectiveEpilogue_; + using ElementC = typename CollectiveEpilogue::ElementC; + using StrideC = typename CollectiveEpilogue::StrideC; + using ElementD = typename CollectiveEpilogue::ElementD; + using StrideD = typename CollectiveEpilogue::StrideD; + using EpilogueArguments = typename CollectiveEpilogue::Arguments; + using EpilogueParams = typename CollectiveEpilogue::Params; + + static_assert(ArchTag::kMinComputeCapability >= 90); + + static constexpr uint32_t TileSchedulerPipelineStageCount = + DispatchPolicy::Schedule::SchedulerPipelineStageCount; + using TileSchedulerTag = TileSchedulerTag_; + + using TileScheduler = typename cutlass::gemm::kernel::detail::TileSchedulerSelector< + TileSchedulerTag, ArchTag, TileShape, ClusterShape, TileSchedulerPipelineStageCount>::Scheduler; + + using TileSchedulerArguments = typename TileScheduler::Arguments; + using TileSchedulerParams = typename TileScheduler::Params; + + // Warp specialization thread count per threadblock + static constexpr uint32_t NumSchedThreads = cutlass::NumThreadsPerWarp; // 1 warp + static constexpr uint32_t NumMMAThreads = cute::size(TiledMma{}); // 8 warps + static constexpr uint32_t NumMainloopLoadThreads = cutlass::NumThreadsPerWarp; // 1 warp + static constexpr uint32_t NumEpilogueLoadThreads = cutlass::NumThreadsPerWarp; // 1 warp for C + + static constexpr bool IsSchedDynamicPersistent = TileScheduler::IsDynamicPersistent; + static constexpr bool IsGdcEnabled = cutlass::arch::IsGdcGloballyEnabled; + + static constexpr uint32_t NumLoadWarpGroups = 1; + static constexpr uint32_t NumMmaWarpGroups = NumMMAThreads / cutlass::NumThreadsPerWarpGroup; + static constexpr uint32_t MaxThreadsPerBlock = + NumMMAThreads + (NumLoadWarpGroups * cutlass::NumThreadsPerWarpGroup); + static constexpr uint32_t MinBlocksPerMultiprocessor = 1; + static constexpr uint32_t NumFixupBarriers = NumMmaWarpGroups; + static constexpr uint32_t NumProducerThreads = CollectiveMainloop::NumProducerThreadEvents; + static constexpr bool IsMainloopAuxiliaryLoadNeeded = + cutlass::gemm::kernel::detail::HasAuxiliaryLoad_v; + + /// Register requirement for Load and Math WGs + static constexpr int RegsPerThread = cute::size<0>(TileShape{}) * cute::size<1>(TileShape{}) + / NumMMAThreads * sizeof(ElementAccumulator) + / sizeof(uint32_t); + static constexpr bool HeavyRegisterPressure = RegsPerThread >= 208; + static constexpr uint32_t LoadRegisterRequirement = !HeavyRegisterPressure ? 40 : 24; + static constexpr uint32_t MmaRegisterRequirement = !HeavyRegisterPressure ? 232 : 240; + + // 1 stage ordered sequence between mainloop and epilogue producer load threads + using LoadWarpOrderBarrier = cutlass::OrderedSequenceBarrier<1, 2>; + + using TileSchedulerPipeline = typename TileScheduler::Pipeline; + using TileSchedulerPipelineState = typename TileSchedulerPipeline::PipelineState; + using TileSchedulerStorage = typename TileScheduler::SharedStorage; + using TileSchedulerThrottlePipeline = typename TileScheduler::ThrottlePipeline; + using TileSchedulerThrottlePipelineState = typename TileSchedulerThrottlePipeline::PipelineState; + + // Kernel level shared memory storage + struct SharedStorage { + struct PipelineStorage : cute::aligned_struct<16, cute::_1> { + using MainloopPipelineStorage = typename CollectiveMainloop::PipelineStorage; + using EpiLoadPipelineStorage = typename CollectiveEpilogue::PipelineStorage; + + alignas(16) MainloopPipelineStorage mainloop; + alignas(16) EpiLoadPipelineStorage epi_load; + alignas(16) typename LoadWarpOrderBarrier::SharedStorage load_order; + } pipelines; + + alignas(16) TileSchedulerStorage scheduler; + + struct TensorStorage : cute::aligned_struct<128, cute::_1> { + using MainloopTensorStorage = typename CollectiveMainloop::TensorStorage; + using EpilogueTensorStorage = typename CollectiveEpilogue::TensorStorage; + + EpilogueTensorStorage epilogue; + MainloopTensorStorage mainloop; + } tensors; + }; + + static constexpr int SharedStorageSize = sizeof(SharedStorage); + + // Device side arguments + struct Arguments { + cutlass::gemm::GemmUniversalMode mode{}; + ProblemShape problem_shape{}; + MainloopArguments mainloop{}; + EpilogueArguments epilogue{}; + cutlass::KernelHardwareInfo hw_info{}; + TileSchedulerArguments scheduler{}; + }; + + // Kernel entry point API + struct Params { + cutlass::gemm::GemmUniversalMode mode{}; + ProblemShape problem_shape{}; + MainloopParams mainloop{}; + EpilogueParams epilogue{}; + cutlass::KernelHardwareInfo hw_info{}; + TileSchedulerParams scheduler{}; + void* workspace{ nullptr }; + }; + + // + // Methods + // + + static bool can_implement(Arguments const& args) + { + bool implementable = (args.mode == cutlass::gemm::GemmUniversalMode::kGemm) + or (args.mode == cutlass::gemm::GemmUniversalMode::kBatched + && cute::rank(ProblemShape{}) == 4); + if (!implementable) { + CUTLASS_TRACE_HOST( + " CAN IMPLEMENT: Arguments or Problem Shape don't meet the requirements.\n"); + return implementable; + } + implementable &= CollectiveMainloop::can_implement(args.problem_shape, args.mainloop); + implementable &= CollectiveEpilogue::can_implement(args.problem_shape, args.epilogue); + implementable &= TileScheduler::can_implement(args.scheduler); + return implementable; + } + + static dim3 get_block_shape() { return dim3(MaxThreadsPerBlock, 1, 1); } + + // Computes the kernel launch grid shape based on runtime parameters + static dim3 get_grid_shape(Params const& params) + { + // Given device SM count, set grid size s.t. we do not launch more thread blocks than we can run concurrently + TileSchedulerArguments args{}; + if constexpr (!std::is_const_v) { + args.max_swizzle_size = 1 << params.scheduler.log_swizzle_size_; + } + args.raster_order = params.scheduler.raster_order_ == TileScheduler::RasterOrder::AlongN + ? TileScheduler::RasterOrderOptions::AlongN + : TileScheduler::RasterOrderOptions::AlongM; + return TileScheduler::get_grid_shape(params.scheduler, params.problem_shape, TileShape{}, + ClusterShape{}, params.hw_info, args); + } + + static size_t get_workspace_size(Arguments const& args) + { + size_t workspace_size = 0; + constexpr uint32_t NumEpilogueSubTiles = + CollectiveEpilogue::get_store_pipe_increment(TileShape{}); + + workspace_size += CollectiveEpilogue::get_workspace_size(args.problem_shape, args.epilogue); + workspace_size = cutlass::round_nearest(workspace_size, cutlass::MinWorkspaceAlignment); + + workspace_size += TileScheduler::template get_workspace_size( + args.scheduler, args.problem_shape, args.hw_info, NumMmaWarpGroups, NumEpilogueSubTiles); + workspace_size = cutlass::round_nearest(workspace_size, cutlass::MinWorkspaceAlignment); + return workspace_size; + } + + static cutlass::Status initialize_workspace(Arguments const& args, void* workspace = nullptr, + cudaStream_t stream = nullptr, + cutlass::CudaHostAdapter* cuda_adapter = nullptr) + { + cutlass::Status status = cutlass::Status::kSuccess; + uint8_t* workspace_ptr = reinterpret_cast(workspace); + size_t workspace_offset = 0; + constexpr uint32_t NumEpilogueSubTiles = + CollectiveEpilogue::get_store_pipe_increment(TileShape{}); + static constexpr uint32_t NumAccumulatorMtxs = 1; + + status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, + workspace_ptr + workspace_offset, stream, + cuda_adapter); + workspace_offset += CollectiveEpilogue::get_workspace_size(args.problem_shape, args.epilogue); + workspace_offset = cutlass::round_nearest(workspace_offset, cutlass::MinWorkspaceAlignment); + if (status != cutlass::Status::kSuccess) { + return status; + } + + status = TileScheduler::template initialize_workspace( + args.scheduler, workspace_ptr + workspace_offset, stream, args.problem_shape, + args.hw_info, NumMmaWarpGroups, NumEpilogueSubTiles, NumAccumulatorMtxs, cuda_adapter); + workspace_offset += TileScheduler::template get_workspace_size( + args.scheduler, args.problem_shape, args.hw_info, NumMmaWarpGroups, NumEpilogueSubTiles); + workspace_offset = cutlass::round_nearest(workspace_offset, cutlass::MinWorkspaceAlignment); + if (status != cutlass::Status::kSuccess) { + return status; + } + + return status; + } + + CUTLASS_DEVICE + void operator()(Params const& params, char* smem_buf) + { +#ifdef __CUDA_ARCH_FEAT_SM90_ALL + #define ENABLE_SM90_KERNEL_LEVEL 1 +#endif +// Any Tensor Op MMA Atom in the ISA is arch conditional. +#ifndef ENABLE_SM90_KERNEL_LEVEL + printf( + "ERROR : Arch conditional MMA instruction used without targeting appropriate compute " + "capability. Aborting.\n"); +#else + + // Preconditions + static_assert(NumMMAThreads == 256, + "Cooperative kernel must have TiledMMA operating using 256 threads."); + static_assert(cute::size<0>(TileShape{}) >= 128, + "Cooperative kernel requires Tile Size to be greater than or equal to 128 " + "along the M-dimension."); + + static_assert(cute::rank(StrideA{}) == 3, + "StrideA must be rank-3: [M, K, L]. If batch mode is not needed, set L " + "stride to Int<0>."); + static_assert(cute::rank(StrideB{}) == 3, + "StrideB must be rank-3: [N, K, L]. If batch mode is not needed, set L " + "stride to Int<0>."); + static_assert(cute::rank(StrideC{}) == 3, + "StrideC must be rank-3: [M, N, L]. If batch mode is not needed, set L " + "stride to Int<0>."); + static_assert(cute::rank(StrideD{}) == 3, + "StrideD must be rank-3: [M, N, L]. If batch mode is not needed, set L " + "stride to Int<0>."); + + /* In the Cooperative kernel, Consumer0 and Consumer1 collaborate on the same tile */ + enum class WarpGroupRole { Producer = 0, Consumer0 = 1, Consumer1 = 2 }; + enum class ProducerWarpRole { Mainloop = 0, Warp1 = 1, Epilogue = 2, MainloopAux = 3 }; + + // Kernel level shared memory storage + SharedStorage& shared_storage = *reinterpret_cast(smem_buf); + + int thread_idx = int(threadIdx.x); + int lane_idx = cutlass::canonical_lane_idx(); + int warp_idx = cutlass::canonical_warp_idx_sync(); + int warp_idx_in_warp_group = warp_idx % cutlass::NumWarpsPerWarpGroup; + int warp_group_thread_idx = thread_idx % cutlass::NumThreadsPerWarpGroup; + int mma_thread_idx = thread_idx % NumMMAThreads; + auto warp_group_role = WarpGroupRole(cutlass::canonical_warp_group_idx()); + auto producer_warp_role = ProducerWarpRole(warp_idx_in_warp_group); + int lane_predicate = cute::elect_one_sync(); + uint32_t block_rank_in_cluster = cute::block_rank_in_cluster(); + + // Issue Tma Descriptor Prefetch from a single thread + if ((warp_idx == 0) && lane_predicate) { + CollectiveMainloop::prefetch_tma_descriptors(params.mainloop); + CollectiveEpilogue::prefetch_tma_descriptors(params.epilogue); + } + + CollectiveEpilogue collective_epilogue(params.epilogue, shared_storage.tensors.epilogue); + bool is_epi_load_needed = collective_epilogue.is_producer_load_needed(); + // TileScheduler pipeline + typename TileSchedulerPipeline::Params scheduler_pipeline_params; + typename TileSchedulerThrottlePipeline::Params scheduler_throttle_pipeline_params; + if constexpr (IsSchedDynamicPersistent) { + if (warp_group_role == WarpGroupRole::Producer + && producer_warp_role == ProducerWarpRole::Warp1) { + scheduler_pipeline_params.role = TileSchedulerPipeline::ThreadCategory::ProducerConsumer; + } else { + scheduler_pipeline_params.role = TileSchedulerPipeline::ThreadCategory::Consumer; + } + scheduler_pipeline_params.producer_blockid = 0; + scheduler_pipeline_params.producer_arv_count = 1; + scheduler_pipeline_params.consumer_arv_count = + NumSchedThreads + NumMainloopLoadThreads + NumMMAThreads; + + if (is_epi_load_needed) { + scheduler_pipeline_params.consumer_arv_count += NumEpilogueLoadThreads; + } + scheduler_pipeline_params.transaction_bytes = sizeof(typename TileScheduler::CLCResponse); + + scheduler_throttle_pipeline_params.producer_arv_count = NumMainloopLoadThreads; + scheduler_throttle_pipeline_params.consumer_arv_count = NumSchedThreads; + scheduler_throttle_pipeline_params.dst_blockid = 0; + scheduler_throttle_pipeline_params.initializing_warp = 3; + if (warp_group_role == WarpGroupRole::Producer + && producer_warp_role == ProducerWarpRole::Warp1) { + scheduler_throttle_pipeline_params.role = + TileSchedulerThrottlePipeline::ThreadCategory::Consumer; + } + // set role when it is for DMA warp in Mainloop + else if (warp_group_role == WarpGroupRole::Producer + && producer_warp_role == ProducerWarpRole::Mainloop) { + scheduler_throttle_pipeline_params.role = + TileSchedulerThrottlePipeline::ThreadCategory::Producer; + } + } + TileSchedulerPipeline scheduler_pipeline(shared_storage.scheduler.pipeline(), + scheduler_pipeline_params); + TileSchedulerPipelineState scheduler_pipe_consumer_state; + + TileSchedulerThrottlePipeline scheduler_throttle_pipeline( + shared_storage.scheduler.throttle_pipeline(), scheduler_throttle_pipeline_params); + TileSchedulerThrottlePipelineState scheduler_pipe_throttle_consumer_state; + TileSchedulerThrottlePipelineState scheduler_pipe_throttle_producer_state = + cutlass::make_producer_start_state(); + + // Mainloop Load pipeline + using MainloopPipeline = typename CollectiveMainloop::MainloopPipeline; + typename MainloopPipeline::Params mainloop_pipeline_params; + if (warp_group_role == WarpGroupRole::Producer + && (producer_warp_role == ProducerWarpRole::Mainloop + || producer_warp_role == ProducerWarpRole::MainloopAux)) { + mainloop_pipeline_params.role = MainloopPipeline::ThreadCategory::Producer; + } + if (warp_group_role == WarpGroupRole::Consumer0 || warp_group_role == WarpGroupRole::Consumer1) { + mainloop_pipeline_params.role = MainloopPipeline::ThreadCategory::Consumer; + } + mainloop_pipeline_params.is_leader = warp_group_thread_idx == 0; + mainloop_pipeline_params.num_consumers = NumMMAThreads; + mainloop_pipeline_params.num_producers = NumProducerThreads; + mainloop_pipeline_params.transaction_bytes = params.mainloop.tma_transaction_bytes; + MainloopPipeline mainloop_pipeline(shared_storage.pipelines.mainloop, + mainloop_pipeline_params, ClusterShape{}); + + // Epilogue Load pipeline + using EpiLoadPipeline = typename CollectiveEpilogue::LoadPipeline; + typename EpiLoadPipeline::Params epi_load_pipeline_params; + if (warp_group_role == WarpGroupRole::Producer + && producer_warp_role == ProducerWarpRole::Epilogue) { + epi_load_pipeline_params.role = EpiLoadPipeline::ThreadCategory::Producer; + } + if (warp_group_role == WarpGroupRole::Consumer0 || warp_group_role == WarpGroupRole::Consumer1) { + epi_load_pipeline_params.role = EpiLoadPipeline::ThreadCategory::Consumer; + } + epi_load_pipeline_params.dst_blockid = cute::block_rank_in_cluster(); + epi_load_pipeline_params.producer_arv_count = NumEpilogueLoadThreads; + epi_load_pipeline_params.consumer_arv_count = NumMMAThreads; + if constexpr (CollectiveEpilogue::RequiresTransactionBytes) { + epi_load_pipeline_params.transaction_bytes = params.epilogue.tma_transaction_bytes; + } + EpiLoadPipeline epi_load_pipeline(shared_storage.pipelines.epi_load, epi_load_pipeline_params); + + // Epilogue Store pipeline + using EpiStorePipeline = typename CollectiveEpilogue::StorePipeline; + typename EpiStorePipeline::Params epi_store_pipeline_params; + epi_store_pipeline_params.always_wait = true; + EpiStorePipeline epi_store_pipeline(epi_store_pipeline_params); + + typename LoadWarpOrderBarrier::Params params_load_order_barrier; + params_load_order_barrier.group_id = producer_warp_role == ProducerWarpRole::Mainloop ? 0 : 1; + params_load_order_barrier.group_size = cutlass::NumThreadsPerWarp; + LoadWarpOrderBarrier load_order_barrier(shared_storage.pipelines.load_order, + params_load_order_barrier); + + // Initialize starting pipeline states for the collectives + // Epilogue store pipe is producer-only (consumer is TMA unit, waits via scoreboarding) + typename CollectiveMainloop::PipelineState mainloop_pipe_consumer_state; + typename CollectiveEpilogue::LoadPipelineState epi_load_pipe_consumer_state; + + // For the DMA Load (producer) we start with an opposite phase + // i.e., we skip all waits since we know that the buffer is indeed empty + cutlass::PipelineState mainloop_pipe_producer_state = + cutlass::make_producer_start_state(); + cutlass::PipelineState epi_load_pipe_producer_state = + cutlass::make_producer_start_state(); + cutlass::PipelineState epi_store_pipe_producer_state = + cutlass::make_producer_start_state(); + + auto cluster_wait_fn = []() { + // We need this to guarantee that the Pipeline init is visible + // To all producers and consumer thread blocks in the Cluster + if constexpr (cute::size(ClusterShape{}) > 1) { + cute::cluster_arrive_relaxed(); + return []() { cute::cluster_wait(); }; + } else { + __syncthreads(); + return []() {}; // do nothing + } + }(); + + // Optionally append 1s until problem shape is rank-4 in case it is only rank-3 (MNK) + auto problem_shape_MNKL = cute::append<4>(params.problem_shape, cute::_1{}); + + // Get the appropriate blocks for this thread block -- potential for thread block locality + TiledMma tiled_mma; + auto blk_shape = TileShape{}; // (BLK_M,BLK_N,BLK_K) + + TileScheduler scheduler{ params.scheduler }; + if constexpr (IsSchedDynamicPersistent) { + scheduler.set_data_ptr(shared_storage.scheduler.data()); + } + // Declare work_tile_info, then define it in each of warps that use it. + typename TileScheduler::WorkTileInfo work_tile_info; + + // In a warp specialized kernel, collectives expose data movement and compute operations separately + CollectiveMainloop collective_mainloop; + + // Prepare and partition the input tensors. Expects a tuple of tensors where: + // get<0>(load_inputs) is the tma tensor A after local tiling so that it has shape + // (BLK_M,BLK_K,m,k,l) get<1>(load_inputs) is the tma tensor B0 after local tiling so that + // it has shape (BLK_N,BLK_K,n,k,l) get<2>(load_inputs) is the tma tensor B1 after local + // tiling so that it has shape (BLK_N,BLK_K,n,k,l) get<3>(load_inputs) is the tma tensor B2 + // after local tiling so that it has shape (BLK_N,BLK_K,n,k,l) get<4>(load_inputs) is the + // tma tensor B3 after local tiling so that it has shape (BLK_N,BLK_K,n,k,l) + + auto load_inputs = collective_mainloop.load_init(problem_shape_MNKL, params.mainloop); + static_assert(cute::tuple_size_v >= 5, + "Output of load_init must have at least five elements (A, B0, B1, B2, B3)"); + + // Extract out partitioned A and B. + cute::Tensor gA_mkl = cute::get<0>(load_inputs); + cute::Tensor gB0_nkl = cute::get<1>(load_inputs); + cute::Tensor gB1_nkl = cute::get<2>(load_inputs); + cute::Tensor gB2_nkl = cute::get<3>(load_inputs); + cute::Tensor gB3_nkl = cute::get<4>(load_inputs); + + // Wait for all thread blocks in the Cluster + cluster_wait_fn(); + + if (warp_group_role == WarpGroupRole::Producer) { + work_tile_info = scheduler.initial_work_tile_info(ClusterShape{}); + cutlass::arch::warpgroup_reg_dealloc(); + + // Scheduler Producer Warp + if (producer_warp_role == ProducerWarpRole::Warp1) { + if constexpr (IsSchedDynamicPersistent) { + bool requires_clc_query = true; + TileSchedulerPipelineState scheduler_pipe_producer_state = + cutlass::make_producer_start_state(); + + cutlass::arch::wait_on_dependent_grids(); + while (work_tile_info.is_valid()) { + + if (requires_clc_query) { + // Throttle CLC query to mitigate workload imbalance caused by skews among persistent workers. + scheduler_throttle_pipeline.consumer_wait( + scheduler_pipe_throttle_consumer_state); + scheduler_throttle_pipeline.consumer_release( + scheduler_pipe_throttle_consumer_state); + ++scheduler_pipe_throttle_consumer_state; + + // Query next work tile + scheduler_pipe_producer_state = scheduler.advance_to_next_work( + scheduler_pipeline, scheduler_pipe_producer_state); + } + + // Fetch next work tile + auto [next_work_tile_info, increment_pipe] = scheduler.fetch_next_work( + work_tile_info, scheduler_pipeline, scheduler_pipe_consumer_state); + requires_clc_query = increment_pipe; + if (increment_pipe) { + ++scheduler_pipe_consumer_state; + } + + work_tile_info = next_work_tile_info; + } + scheduler_pipeline.producer_tail(scheduler_pipe_producer_state); + } + } // Scheduler Producer Warp End + else + + // Mainloop Producer Warp + if (producer_warp_role == ProducerWarpRole::Mainloop) { + // Ensure that the prefetched kernel does not touch + // unflushed global memory prior to this instruction + cutlass::arch::wait_on_dependent_grids(); + bool do_load_order_arrive = true; + bool requires_clc_query = true; + while (work_tile_info.is_valid()) { + if (!TileScheduler::valid_warpgroup_in_work_tile(work_tile_info)) { + auto [next_work_tile_info, increment_pipe] = + scheduler.fetch_next_work(work_tile_info); + work_tile_info = next_work_tile_info; + continue; + } + + // Compute m_coord, n_coord, l_coord with the post-tiled m-shape and n-shape + auto m_coord = cute::idx2crd(work_tile_info.M_idx, cute::shape<2>(gA_mkl)); + auto n_coord = cute::idx2crd(work_tile_info.N_idx, cute::shape<2>(gB0_nkl)); + auto l_coord = cute::idx2crd(work_tile_info.L_idx, cute::shape<4>(gB0_nkl)); + auto blk_coord = cute::make_coord(m_coord, n_coord, cute::_, l_coord); + + // Get the number of K tiles to compute for this work as well as the starting K tile offset of the work. + auto work_k_tile_count = TileScheduler::get_work_k_tile_count( + work_tile_info, problem_shape_MNKL, blk_shape); + auto work_k_tile_start = TileScheduler::get_work_k_tile_start(work_tile_info); + auto k_tile_iter = cute::make_coord_iterator( + cute::idx2crd(work_k_tile_start, cute::shape<3>(gA_mkl)), + cute::shape<3>(gA_mkl)); + + if (requires_clc_query) { + scheduler_throttle_pipeline.producer_acquire( + scheduler_pipe_throttle_producer_state); + scheduler_throttle_pipeline.producer_commit( + scheduler_pipe_throttle_producer_state); + ++scheduler_pipe_throttle_producer_state; + } + + collective_mainloop.load( + params.mainloop, mainloop_pipeline, mainloop_pipe_producer_state, + load_inputs, blk_coord, k_tile_iter, work_k_tile_count, lane_idx, + block_rank_in_cluster, shared_storage.tensors.mainloop); + // Update starting pipeline state for the next tile + mainloop_pipe_producer_state.advance(work_k_tile_count); + + // Signal for the epilogue load warp to begin + if (do_load_order_arrive) { + load_order_barrier.arrive(); + do_load_order_arrive = false; + } + // Get next work tile + auto [next_work_tile_info, increment_pipe] = scheduler.fetch_next_work( + work_tile_info, scheduler_pipeline, scheduler_pipe_consumer_state); + + work_tile_info = next_work_tile_info; + if constexpr (IsSchedDynamicPersistent) { + requires_clc_query = increment_pipe; + if (increment_pipe) { + ++scheduler_pipe_consumer_state; + } + } + } // Scheduler work fetch loop + + // Make sure all Consumer Warp Groups have been waited upon + collective_mainloop.load_tail(mainloop_pipeline, mainloop_pipe_producer_state); + + } else if (producer_warp_role == ProducerWarpRole::MainloopAux) { + if constexpr (IsMainloopAuxiliaryLoadNeeded) { + while (work_tile_info.is_valid()) { + if (!TileScheduler::valid_warpgroup_in_work_tile(work_tile_info)) { + auto [next_work_tile_info, increment_pipe] = + scheduler.fetch_next_work(work_tile_info); + work_tile_info = next_work_tile_info; + continue; + } + + // Compute m_coord, n_coord, l_coord with the post-tiled m-shape and n-shape + auto m_coord = cute::idx2crd(work_tile_info.M_idx, cute::shape<2>(gA_mkl)); + auto n_coord = + cute::idx2crd(work_tile_info.N_idx, cute::shape<2>(gB0_nkl)); + auto l_coord = + cute::idx2crd(work_tile_info.L_idx, cute::shape<4>(gB0_nkl)); + auto blk_coord = cute::make_coord(m_coord, n_coord, cute::_, l_coord); + + // Get the number of K tiles to compute for this work as well as the starting K tile offset of the work. + auto work_k_tile_count = TileScheduler::get_work_k_tile_count( + work_tile_info, problem_shape_MNKL, blk_shape); + auto work_k_tile_start = + TileScheduler::get_work_k_tile_start(work_tile_info); + auto k_tile_iter = cute::make_coord_iterator( + cute::idx2crd(work_k_tile_start, cute::shape<3>(gA_mkl)), + cute::shape<3>(gA_mkl)); + + collective_mainloop.load_auxiliary( + params.mainloop, mainloop_pipeline, mainloop_pipe_producer_state, + load_inputs, blk_coord, k_tile_iter, work_k_tile_count, lane_idx, + block_rank_in_cluster, shared_storage.tensors.mainloop); + // Update starting pipeline state for the next tile + mainloop_pipe_producer_state.advance(work_k_tile_count); + + // Get next work tile + auto [next_work_tile_info, increment_pipe] = scheduler.fetch_next_work( + work_tile_info, scheduler_pipeline, scheduler_pipe_consumer_state); + + work_tile_info = next_work_tile_info; + } // Scheduler work fetch loop + } + } + + // Epilogue Producer Warp + else if (producer_warp_role == ProducerWarpRole::Epilogue && is_epi_load_needed) { + + // Ensure that the prefetched kernel does not touch + // unflushed global memory prior to this instruction + cutlass::arch::wait_on_dependent_grids(); + + if (!TileScheduler::requires_separate_reduction(params.scheduler) + && work_tile_info.is_valid()) { + load_order_barrier.wait(); + } + + CollectiveEpilogue collective_epilogue(params.epilogue, + shared_storage.tensors.epilogue); + + while (work_tile_info.is_valid()) { + if (TileScheduler::compute_epilogue(work_tile_info, params.scheduler)) { + // Compute m_coord, n_coord, l_coord with the post-tiled m-shape and n-shape + auto m_coord = cute::idx2crd(work_tile_info.M_idx, cute::shape<2>(gA_mkl)); + auto n_coord = + cute::idx2crd(work_tile_info.N_idx, cute::shape<2>(gB0_nkl)); + auto l_coord = + cute::idx2crd(work_tile_info.L_idx, cute::shape<4>(gB0_nkl)); + auto blk_coord = cute::make_coord(m_coord, n_coord, cute::_, l_coord); + + epi_load_pipe_producer_state = collective_epilogue.load( + epi_load_pipeline, epi_load_pipe_producer_state, problem_shape_MNKL, + blk_shape, blk_coord, tiled_mma, lane_idx, + shared_storage.tensors.epilogue, + work_tile_info.reduction_subtile_idx()); + } + + // Get next work tile + auto [next_work_tile_info, increment_pipe] = scheduler.fetch_next_work( + work_tile_info, scheduler_pipeline, scheduler_pipe_consumer_state); + work_tile_info = next_work_tile_info; + if constexpr (IsSchedDynamicPersistent) { + if (increment_pipe) { + ++scheduler_pipe_consumer_state; + } + } + } // Scheduler work fetch loop + + // Make sure all Consumer Warp Groups have been waited upon + collective_epilogue.load_tail(epi_load_pipeline, epi_load_pipe_producer_state); + } // Epilogue Producer Warp End + } // Producer Warp Group End + else if (warp_group_role == WarpGroupRole::Consumer0 + || warp_group_role == WarpGroupRole::Consumer1) { + work_tile_info = scheduler.initial_work_tile_info(ClusterShape{}); + cutlass::arch::warpgroup_reg_alloc(); + + CollectiveEpilogue collective_epilogue(params.epilogue, shared_storage.tensors.epilogue); + + // Do we potentially issue tail arrives for TMA stores, if epilogue load is waiting for it + bool do_store_tail = false; + while (work_tile_info.is_valid()) { + // Compute m_coord, n_coord, l_coord with the post-tiled m-shape and n-shape + auto m_coord = cute::idx2crd(work_tile_info.M_idx, cute::shape<2>(gA_mkl)); + auto n_coord = cute::idx2crd(work_tile_info.N_idx, cute::shape<2>(gB0_nkl)); + auto l_coord = cute::idx2crd(work_tile_info.L_idx, cute::shape<4>(gB0_nkl)); + auto blk_coord = cute::make_coord(m_coord, n_coord, cute::_, l_coord); + auto work_k_tile_count = + TileScheduler::get_work_k_tile_count(work_tile_info, problem_shape_MNKL, blk_shape); + // Allocate the accumulators for the (M,N) blk_shape + // + // MSVC CTAD breaks if we say "Tensor" here, so we use "auto" instead. + auto accumulators0 = + cute::partition_fragment_C(tiled_mma, cute::take<0, 2>(blk_shape)); // (MMA,MMA_M,MMA_N) + auto accumulators1 = + cute::partition_fragment_C(tiled_mma, cute::take<0, 2>(blk_shape)); // (MMA,MMA_M,MMA_N) + auto accumulators2 = + cute::partition_fragment_C(tiled_mma, cute::take<0, 2>(blk_shape)); // (MMA,MMA_M,MMA_N) + auto accumulators3 = + cute::partition_fragment_C(tiled_mma, cute::take<0, 2>(blk_shape)); // (MMA,MMA_M,MMA_N) + + if (TileScheduler::valid_warpgroup_in_work_tile(work_tile_info)) { + collective_mainloop.mma(mainloop_pipeline, mainloop_pipe_consumer_state, + accumulators0, accumulators1, accumulators2, + accumulators3, work_k_tile_count, mma_thread_idx, + shared_storage.tensors.mainloop, params.mainloop); + + // Make sure the math instructions are done and free buffers before entering the epilogue + collective_mainloop.mma_tail(mainloop_pipeline, mainloop_pipe_consumer_state, + work_k_tile_count); + + // Update starting mainloop pipeline state for the next tile + mainloop_pipe_consumer_state.advance(work_k_tile_count); + } + #ifdef CUTLASS_ENABLE_GDC_FOR_SM90 + if (scheduler.is_last_tile(work_tile_info)) { + // Hint on an early release of global memory resources. + // The timing of calling this function only influences performance, + // not functional correctness. + cutlass::arch::launch_dependent_grids(); + } + #endif + + // Index of warp group within consumer warp groups + int consumer_warp_group_idx = cutlass::canonical_warp_group_idx() - NumLoadWarpGroups; + + // Perform reduction across splits, if needed + TileScheduler::fixup(params.scheduler, work_tile_info, accumulators0, + NumMmaWarpGroups, consumer_warp_group_idx); + TileScheduler::fixup(params.scheduler, work_tile_info, accumulators1, + NumMmaWarpGroups, consumer_warp_group_idx); + TileScheduler::fixup(params.scheduler, work_tile_info, accumulators2, + NumMmaWarpGroups, consumer_warp_group_idx); + TileScheduler::fixup(params.scheduler, work_tile_info, accumulators3, + NumMmaWarpGroups, consumer_warp_group_idx); + + if (TileScheduler::compute_epilogue(work_tile_info, params.scheduler)) { + // Epilogue and write to gD + auto [epi_load_pipe_consumer_state_next, epi_store_pipe_producer_state_next] = + collective_epilogue.store( + epi_load_pipeline, epi_load_pipe_consumer_state, epi_store_pipeline, + epi_store_pipe_producer_state, problem_shape_MNKL, blk_shape, blk_coord, + accumulators0, accumulators1, accumulators2, accumulators3, tiled_mma, + mma_thread_idx, shared_storage.tensors.epilogue, + work_tile_info.reduction_subtile_idx()); + epi_load_pipe_consumer_state = epi_load_pipe_consumer_state_next; + epi_store_pipe_producer_state = epi_store_pipe_producer_state_next; + do_store_tail = true; + } + + // Get next work tile + auto [next_work_tile_info, increment_pipe] = scheduler.fetch_next_work( + work_tile_info, scheduler_pipeline, scheduler_pipe_consumer_state); + work_tile_info = next_work_tile_info; + if constexpr (IsSchedDynamicPersistent) { + if (increment_pipe) { + ++scheduler_pipe_consumer_state; + } + } + } // Scheduler work fetch loop + + if (do_store_tail) { + collective_epilogue.store_tail(epi_load_pipeline, epi_load_pipe_consumer_state, + epi_store_pipeline, epi_store_pipe_producer_state); + } + } // Consumer Warp Groups End +#endif + } + + // Convert to underlying arguments. In this case, a simple copy for the aliased type. + static Params to_underlying_arguments(Arguments const& args, void* workspace) + { + CUTLASS_TRACE_HOST("to_underlying_arguments():"); + + auto problem_shape = args.problem_shape; + if constexpr (cutlass::gemm::kernel::detail::Has_SwapAB_v) { + // swap M/N + cute::get<0>(problem_shape) = cute::get<1>(args.problem_shape); + cute::get<1>(problem_shape) = cute::get<0>(args.problem_shape); + } + auto problem_shape_MNKL = cute::append<4>(problem_shape, 1); + + // Get SM count if needed, otherwise use user supplied SM count + int sm_count = args.hw_info.sm_count; + if (sm_count <= 0) { + CUTLASS_TRACE_HOST( + " WARNING: Arguments do not include a valid SM count.\n" + " For optimal performance, populate the arguments KernelHardwareInfo struct with " + "the SM count."); + sm_count = + cutlass::KernelHardwareInfo::query_device_multiprocessor_count(args.hw_info.device_id); + } + CUTLASS_TRACE_HOST("to_underlying_arguments(): Setting persistent grid SM count to " + << sm_count); + + // Get maximum number of clusters that could co-exist on the target device + int max_active_clusters = args.hw_info.max_active_clusters; + if (max_active_clusters <= 0) { + max_active_clusters = 0; + CUTLASS_TRACE_HOST( + " WARNING: Arguments do not include a valid max cluster count.\n" + " For optimal performance, populate the arguments KernelHardwareInfo struct with " + "the max_active_clusters."); + } else { + CUTLASS_TRACE_HOST( + "to_underlying_arguments(): Setting persistent grid cluster count to " + << max_active_clusters); + } + + cutlass::KernelHardwareInfo hw_info{ args.hw_info.device_id, sm_count, max_active_clusters }; + + // Calculate workspace pointers + uint8_t* workspace_ptr = reinterpret_cast(workspace); + size_t workspace_offset = 0; + + void* epilogue_workspace = workspace_ptr + workspace_offset; + workspace_offset += CollectiveEpilogue::get_workspace_size(args.problem_shape, args.epilogue); + workspace_offset = cutlass::round_nearest(workspace_offset, cutlass::MinWorkspaceAlignment); + + void* scheduler_workspace = workspace_ptr + workspace_offset; + workspace_offset += + TileScheduler::template get_workspace_size( + args.scheduler, args.problem_shape, args.hw_info, NumMmaWarpGroups); + workspace_offset = cutlass::round_nearest(workspace_offset, cutlass::MinWorkspaceAlignment); + + void* mainloop_workspace = nullptr; + // Precompute the sub tiles numbers in epilogue, pass into tile scheduler. Therefore it will be used + // in separate reduction scheme for streamk case, NumEpilogueSubTiles default value is 1, which means + // subtile will not be used, therefore separate reduction will not be enabled. + constexpr uint32_t NumEpilogueSubTiles = + CollectiveEpilogue::get_store_pipe_increment(TileShape{}); + TileSchedulerParams scheduler = TileScheduler::to_underlying_arguments( + problem_shape_MNKL, TileShape{}, ClusterShape{}, hw_info, args.scheduler, + scheduler_workspace, NumEpilogueSubTiles); + + return { args.mode, + problem_shape, + CollectiveMainloop::to_underlying_arguments(args.problem_shape, args.mainloop, + mainloop_workspace), + CollectiveEpilogue::to_underlying_arguments(args.problem_shape, args.epilogue, + epilogue_workspace), + hw_info, + scheduler, + workspace }; + } +}; diff --git a/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_mma_tma_gmma_ss_warpspecialized_quad.h b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_mma_tma_gmma_ss_warpspecialized_quad.h new file mode 100644 index 0000000..4e3350c --- /dev/null +++ b/src/layers/extensions/inference/cutlass/sm90_quad_gemm/sm90_mma_tma_gmma_ss_warpspecialized_quad.h @@ -0,0 +1,729 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +// clang-format on + +/** + * These 1 classes/structs are rewritten: + * 1. cutlass::gemm::collective::CollectiveMma -> QuadCollectiveMma + */ + +// Primary template declaration to enable partial/specialized definitions below. +template +struct QuadCollectiveMma { + static_assert(cutlass::detail::dependent_false, + "Could not find a mainloop specialization."); +}; + +// Original file: cutlass/gemm/collective/sm90_mma_tma_gmma_ss_warpspecialized.hpp +// to add multiple accumulators to mma +// WarpSpecialized Mainloop +template +struct QuadCollectiveMma< + cutlass::gemm::MainloopSm90TmaGmmaWarpSpecialized, + TileShape_, ElementA_, StrideA_, ElementB_, StrideB_, TiledMma_, GmemTiledCopyA_, SmemLayoutAtomA_, + SmemCopyAtomA_, TransformA_, GmemTiledCopyB_, SmemLayoutAtomB_, SmemCopyAtomB_, TransformB_> { + // + // Type Aliases + // + using DispatchPolicy = + cutlass::gemm::MainloopSm90TmaGmmaWarpSpecialized; + using TileShape = TileShape_; + using ElementA = ElementA_; + using StrideA = StrideA_; + using ElementB = ElementB_; + using StrideB = StrideB_; + using TiledMma = TiledMma_; + using ElementAccumulator = typename TiledMma::ValTypeC; + using GmemTiledCopyA = GmemTiledCopyA_; + using GmemTiledCopyB = GmemTiledCopyB_; + using SmemLayoutAtomA = SmemLayoutAtomA_; + using SmemLayoutAtomB = SmemLayoutAtomB_; + using SmemCopyAtomA = SmemCopyAtomA_; + using SmemCopyAtomB = SmemCopyAtomB_; + using TransformA = TransformA_; + using TransformB = TransformB_; + using ArchTag = typename DispatchPolicy::ArchTag; + + using CtaShape_MNK = decltype(shape_div(TileShape{}, ClusterShape{})); + using MainloopPipeline = cutlass::PipelineTmaAsync; + using PipelineState = cutlass::PipelineState; + + using PipelineParams = typename MainloopPipeline::Params; + + // One threads per CTA are producers (1 for operand tile) + static constexpr int NumProducerThreadEvents = 1; + + static_assert(cute::rank(SmemLayoutAtomA{}) == 2, "SmemLayoutAtom must be rank 2 (M/N, K)"); + static_assert((cute::size<0>(TileShape{}) % cute::size<0>(SmemLayoutAtomA{})) == 0, + "SmemLayoutAtom must evenly divide tile shape."); + static_assert((cute::size<2>(TileShape{}) % cute::size<1>(SmemLayoutAtomA{})) == 0, + "SmemLayoutAtom must evenly divide tile shape."); + + static_assert(cute::rank(SmemLayoutAtomB{}) == 2, "SmemLayoutAtom must be rank 2 (M/N, K)"); + static_assert((cute::size<1>(TileShape{}) % cute::size<0>(SmemLayoutAtomB{})) == 0, + "SmemLayoutAtom must evenly divide tile shape."); + static_assert((cute::size<2>(TileShape{}) % cute::size<1>(SmemLayoutAtomB{})) == 0, + "SmemLayoutAtom must evenly divide tile shape."); + + // Tile along modes in a way that maximizes the TMA box size. + using SmemLayoutA = decltype(cute::tile_to_shape( + SmemLayoutAtomA{}, + cute::make_shape(cute::shape<0>(TileShape{}), cute::shape<2>(TileShape{}), + cute::Int{}), + cute::conditional_t<::cutlass::gemm::detail::is_major<0, StrideA>(), + cute::Step, + cute::Step>{})); + using SmemLayoutB = decltype(cute::tile_to_shape( + SmemLayoutAtomB{}, + cute::make_shape(cute::shape<1>(TileShape{}), cute::shape<2>(TileShape{}), + cute::Int{}), + cute::conditional_t<::cutlass::gemm::detail::is_major<0, StrideB>(), + cute::Step, + cute::Step>{})); + + static_assert(DispatchPolicy::Stages >= 2, + "Specialization requires Stages set to value 2 or more."); + static_assert(cute::is_base_of::value + && cute::is_base_of::value, + "MMA atom must source both A and B operand from smem_desc for this mainloop."); + static_assert(cute::is_same_v + || cute::is_same_v, + "GmemTiledCopy - invalid SM90 TMA copy atom specified."); + static_assert(cute::is_same_v + || cute::is_same_v, + "GmemTiledCopy - invalid SM90 TMA copy atom specified."); + + // TMA converts f32 input to tf32 when copying from GMEM to SMEM + // For all other types, cast to size equivalent uint type to avoid any rounding by TMA. + static constexpr bool ConvertF32toTF32A = cute::is_same_v; + static constexpr bool ConvertF32toTF32B = cute::is_same_v; + using InternalElementA = cute::conditional_t>>; + using InternalElementB = cute::conditional_t>>; + + struct SharedStorage { + struct TensorStorage : cute::aligned_struct<128, cute::_0> { + cute::array_aligned> smem_A; + cute::array_aligned> smem_B0; + cute::array_aligned> smem_B1; + cute::array_aligned> smem_B2; + cute::array_aligned> smem_B3; + } tensors; + + using PipelineStorage = typename MainloopPipeline::SharedStorage; + PipelineStorage pipeline; + }; + using TensorStorage = typename SharedStorage::TensorStorage; + using PipelineStorage = typename SharedStorage::PipelineStorage; + + // Host side kernel arguments + struct Arguments { + ElementA const* ptr_A; + StrideA dA; + ElementB const* ptr_B0; + ElementB const* ptr_B1; + ElementB const* ptr_B2; + ElementB const* ptr_B3; + StrideB dB; + uint32_t mma_promotion_interval = 4; + }; + + // Device side kernel params + struct Params { + // Assumption: StrideA is congruent with Problem_MK + using TMA_A = decltype(cute::make_tma_copy_A_sm90( + GmemTiledCopyA{}, + cute::make_tensor(static_cast(nullptr), + repeat_like(StrideA{}, int32_t(0)), StrideA{}), + SmemLayoutA{}(cute::_, cute::_, cute::_0{}), TileShape{}, ClusterShape{})); + // Assumption: StrideB is congruent with Problem_NK + using TMA_B = decltype(cute::make_tma_copy_B_sm90( + GmemTiledCopyB{}, + cute::make_tensor(static_cast(nullptr), + repeat_like(StrideB{}, int32_t(0)), StrideB{}), + SmemLayoutB{}(cute::_, cute::_, cute::_0{}), TileShape{}, ClusterShape{})); + TMA_A tma_load_a; + TMA_B tma_load_b0; + TMA_B tma_load_b1; + TMA_B tma_load_b2; + TMA_B tma_load_b3; + + uint32_t tma_transaction_bytes = TmaTransactionBytes; + uint32_t tma_transaction_bytes_mk = TmaTransactionBytesMK; + uint32_t tma_transaction_bytes_nk = TmaTransactionBytesNK; + }; + + // + // Methods + // + + template + static bool can_implement(ProblemShape const& problem_shape, [[maybe_unused]] Arguments const& args) + { + constexpr int tma_alignment_bits = 128; + auto problem_shape_MNKL = cute::append<4>(problem_shape, 1); + auto [M, N, K, L] = problem_shape_MNKL; + + bool implementable = true; + constexpr int min_tma_aligned_elements_A = + tma_alignment_bits / cutlass::sizeof_bits::value; + implementable = implementable + && cutlass::detail::check_alignment( + cute::make_shape(M, K, L), StrideA{}); + constexpr int min_tma_aligned_elements_B = + tma_alignment_bits / cutlass::sizeof_bits::value; + implementable = implementable + && cutlass::detail::check_alignment( + cute::make_shape(N, K, L), StrideB{}); + + if (!implementable) { + CUTLASS_TRACE_HOST( + " CAN IMPLEMENT: Problem Size doesn't meet the minimum alignment requirements for " + "TMA.\n"); + } + return implementable; + } + + static constexpr int K_PIPE_MAX = DispatchPolicy::Stages; + static constexpr int K_PIPE_MMAS = 1; + static constexpr uint32_t TmaTransactionBytesMK = + cutlass::bits_to_bytes(cute::size<0>(SmemLayoutA{}) * cute::size<1>(SmemLayoutA{}) + * static_cast(cutlass::sizeof_bits::value)); + static constexpr uint32_t TmaTransactionBytesNK = + cutlass::bits_to_bytes(cute::size<0>(SmemLayoutB{}) * cute::size<1>(SmemLayoutB{}) + * static_cast(cutlass::sizeof_bits::value)); + static constexpr uint32_t TmaTransactionBytes = TmaTransactionBytesMK + TmaTransactionBytesNK * 4; + + /// Perform a collective-scoped matrix multiply-accumulate + /// Producer Perspective + template + CUTLASS_DEVICE void + load(Params const& mainloop_params, MainloopPipeline pipeline, PipelineState smem_pipe_write, + cute::tuple const& load_inputs, + BlockCoord const& blk_coord, KTileIterator k_tile_iter, int k_tile_count, int thread_idx, + uint32_t block_rank_in_cluster, TensorStorage& shared_tensors) + { + int lane_predicate = cute::elect_one_sync(); + + if (lane_predicate) { + cute::Tensor sA = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_A.data()), + SmemLayoutA{}); // (BLK_M,BLK_K,PIPE) + cute::Tensor sB0 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B0.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + cute::Tensor sB1 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B1.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + cute::Tensor sB2 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B2.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + cute::Tensor sB3 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B3.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + + // + // Prepare the TMA loads for A and B + // + + constexpr uint32_t cluster_shape_x = cute::get<0>(typename DispatchPolicy::ClusterShape()); + uint2 cluster_local_block_id = { block_rank_in_cluster % cluster_shape_x, + block_rank_in_cluster / cluster_shape_x }; + + cute::Tensor gA_mkl = cute::get<0>(load_inputs); + cute::Tensor gB0_nkl = cute::get<1>(load_inputs); + cute::Tensor gB1_nkl = cute::get<2>(load_inputs); + cute::Tensor gB2_nkl = cute::get<3>(load_inputs); + cute::Tensor gB3_nkl = cute::get<4>(load_inputs); + + auto block_tma_a = mainloop_params.tma_load_a.get_slice(cluster_local_block_id.y); + auto block_tma_b0 = mainloop_params.tma_load_b0.get_slice(cluster_local_block_id.x); + auto block_tma_b1 = mainloop_params.tma_load_b1.get_slice(cluster_local_block_id.x); + auto block_tma_b2 = mainloop_params.tma_load_b2.get_slice(cluster_local_block_id.x); + auto block_tma_b3 = mainloop_params.tma_load_b3.get_slice(cluster_local_block_id.x); + + // Partition the inputs based on the current block coordinates. + auto [m_coord, n_coord, k_coord, l_coord] = blk_coord; + cute::Tensor gA = gA_mkl(cute::_, cute::_, m_coord, cute::_, l_coord); // (BLK_M,BLK_K,k) + cute::Tensor gB0 = gB0_nkl(cute::_, cute::_, n_coord, cute::_, l_coord); // (BLK_N,BLK_K,k) + cute::Tensor gB1 = gB1_nkl(cute::_, cute::_, n_coord, cute::_, l_coord); // (BLK_N,BLK_K,k) + cute::Tensor gB2 = gB2_nkl(cute::_, cute::_, n_coord, cute::_, l_coord); // (BLK_N,BLK_K,k) + cute::Tensor gB3 = gB3_nkl(cute::_, cute::_, n_coord, cute::_, l_coord); // (BLK_N,BLK_K,k) + + // Applies the mapping from block_tma_a + cute::Tensor tAgA = block_tma_a.partition_S(gA); // (TMA,TMA_M,TMA_K,k) + cute::Tensor tAsA = block_tma_a.partition_D(sA); // (TMA,TMA_M,TMA_K,PIPE) + + cute::Tensor tBgB0 = block_tma_b0.partition_S(gB0); // (TMA,TMA_N,TMA_K,k) + cute::Tensor tBsB0 = block_tma_b0.partition_D(sB0); // (TMA,TMA_N,TMA_K,PIPE) + cute::Tensor tBgB1 = block_tma_b1.partition_S(gB1); // (TMA,TMA_N,TMA_K,k) + cute::Tensor tBsB1 = block_tma_b1.partition_D(sB1); // (TMA,TMA_N,TMA_K,PIPE) + cute::Tensor tBgB2 = block_tma_b2.partition_S(gB2); // (TMA,TMA_N,TMA_K,k) + cute::Tensor tBsB2 = block_tma_b2.partition_D(sB2); // (TMA,TMA_N,TMA_K,PIPE) + cute::Tensor tBgB3 = block_tma_b3.partition_S(gB3); // (TMA,TMA_N,TMA_K,k) + cute::Tensor tBsB3 = block_tma_b3.partition_D(sB3); // (TMA,TMA_N,TMA_K,PIPE) + + uint16_t mcast_mask_a = 0; + uint16_t mcast_mask_b = 0; + + // Issue TmaLoads + // Maps the tile -> block, value + if constexpr (cute::is_same_v) { + auto block_layout = + cute::Layout{}; // (m,n) -> block_id + for (int n = 0; n < cute::size<1>(block_layout); ++n) { + mcast_mask_a |= + (uint16_t(1) << block_layout(cluster_local_block_id.x, n, cute::_0{})); + } + } + + if constexpr (cute::is_same_v) { + auto block_layout = + cute::Layout{}; // (m,n) -> block_id + for (int m = 0; m < cute::size<0>(block_layout); ++m) { + mcast_mask_b |= + (uint16_t(1) << block_layout(m, cluster_local_block_id.y, cute::_0{})); + } + } + + // Mainloop + CUTLASS_PRAGMA_NO_UNROLL + for (; k_tile_count > 0; --k_tile_count) { + // LOCK smem_pipe_write for _writing_ + pipeline.producer_acquire(smem_pipe_write); + + // + // Copy gmem to smem for *k_tile_iter + // + + using BarrierType = typename MainloopPipeline::ProducerBarrierType; + BarrierType* tma_barrier = pipeline.producer_get_barrier(smem_pipe_write); + + int write_stage = smem_pipe_write.index(); + copy(mainloop_params.tma_load_a.with(*tma_barrier, mcast_mask_a), + tAgA(cute::_, cute::_, cute::_, *k_tile_iter), + tAsA(cute::_, cute::_, cute::_, write_stage)); + copy(mainloop_params.tma_load_b0.with(*tma_barrier, mcast_mask_b), + tBgB0(cute::_, cute::_, cute::_, *k_tile_iter), + tBsB0(cute::_, cute::_, cute::_, write_stage)); + copy(mainloop_params.tma_load_b1.with(*tma_barrier, mcast_mask_b), + tBgB1(cute::_, cute::_, cute::_, *k_tile_iter), + tBsB1(cute::_, cute::_, cute::_, write_stage)); + copy(mainloop_params.tma_load_b2.with(*tma_barrier, mcast_mask_b), + tBgB2(cute::_, cute::_, cute::_, *k_tile_iter), + tBsB2(cute::_, cute::_, cute::_, write_stage)); + copy(mainloop_params.tma_load_b3.with(*tma_barrier, mcast_mask_b), + tBgB3(cute::_, cute::_, cute::_, *k_tile_iter), + tBsB3(cute::_, cute::_, cute::_, write_stage)); + + ++k_tile_iter; + + // Advance smem_pipe_write + ++smem_pipe_write; + } + } + } + + /// Set up the data needed by this collective for load and mma. + /// Returns a tuple of tensors. The collective and the kernel layer have the contract + /// Returned tuple must contain at least two elements, with the first two elements being: + /// gA_mkl - The tma tensor, A after a local tile so it has shape (BLK_M,BLK_K,m,k,l) + /// gB0_nkl - The tma tensor, B after a local tile so it has shape (BLK_N,BLK_K,n,k,l) + /// gB1_nkl - The tma tensor, B after a local tile so it has shape (BLK_N,BLK_K,n,k,l) + /// gB2_nkl - The tma tensor, B after a local tile so it has shape (BLK_N,BLK_K,n,k,l) + /// gB3_nkl - The tma tensor, B after a local tile so it has shape (BLK_N,BLK_K,n,k,l) + + /// The rest of the tensors can be specified as needed by this collective. + template + CUTLASS_DEVICE auto load_init(ProblemShape_MNKL const& problem_shape_MNKL, + Params const& mainloop_params) const + { + // Separate out problem shape for convenience + auto [M, N, K, L] = problem_shape_MNKL; + + // TMA requires special handling of strides to deal with coord codomain mapping + // Represent the full tensors -- get these from TMA + cute::Tensor mA_mkl = + mainloop_params.tma_load_a.get_tma_tensor(cute::make_shape(M, K, L)); // (m,k,l) + cute::Tensor mB0_nkl = + mainloop_params.tma_load_b0.get_tma_tensor(cute::make_shape(N, K, L)); // (n,k,l) + cute::Tensor mB1_nkl = + mainloop_params.tma_load_b1.get_tma_tensor(cute::make_shape(N, K, L)); // (n,k,l) + cute::Tensor mB2_nkl = + mainloop_params.tma_load_b2.get_tma_tensor(cute::make_shape(N, K, L)); // (n,k,l) + cute::Tensor mB3_nkl = + mainloop_params.tma_load_b3.get_tma_tensor(cute::make_shape(N, K, L)); // (n,k,l) + + // Make tiled views, defer the slice + cute::Tensor gA_mkl = + cute::local_tile(mA_mkl, TileShape{}, make_coord(cute::_, cute::_, cute::_), + cute::Step{}); // (BLK_M,BLK_K,m,k,l) + cute::Tensor gB0_nkl = + cute::local_tile(mB0_nkl, TileShape{}, make_coord(cute::_, cute::_, cute::_), + cute::Step{}); // (BLK_N,BLK_K,n,k,l) + cute::Tensor gB1_nkl = + cute::local_tile(mB1_nkl, TileShape{}, make_coord(cute::_, cute::_, cute::_), + cute::Step{}); // (BLK_N,BLK_K,n,k,l) + cute::Tensor gB2_nkl = + cute::local_tile(mB2_nkl, TileShape{}, make_coord(cute::_, cute::_, cute::_), + cute::Step{}); // (BLK_N,BLK_K,n,k,l) + cute::Tensor gB3_nkl = + cute::local_tile(mB3_nkl, TileShape{}, make_coord(cute::_, cute::_, cute::_), + cute::Step{}); // (BLK_N,BLK_K,n,k,l) + + return cute::make_tuple(gA_mkl, gB0_nkl, gB1_nkl, gB2_nkl, gB3_nkl); + } + + /// Perform a Producer Epilogue to prevent early exit of blocks in a Cluster + CUTLASS_DEVICE void load_tail(MainloopPipeline pipeline, PipelineState smem_pipe_write) + { + int lane_predicate = cute::elect_one_sync(); + + // Issue the epilogue waits + if (lane_predicate) { + /* This helps avoid early exit of blocks in Cluster + * Waits for all stages to either be released (all + * Consumer UNLOCKs), or if the stage was never used + * then would just be acquired since the phase was + * still inverted from make_producer_start_state + */ + pipeline.producer_tail(smem_pipe_write); + } + } + + /// Perform a collective-scoped matrix multiply-accumulate + /// Consumer Perspective + template + CUTLASS_DEVICE void mma(MainloopPipeline pipeline, PipelineState smem_pipe_read, + FrgTensorC& accum0, FrgTensorC& accum1, FrgTensorC& accum2, + FrgTensorC& accum3, int k_tile_count, int thread_idx, + TensorStorage& shared_tensors, Params const& mainloop_params) + { + static_assert(cute::is_rmem::value, "C tensor must be rmem resident."); + static_assert(cute::rank(SmemLayoutA{}) == 3, "Smem layout must be rank 3."); + static_assert(cute::rank(SmemLayoutB{}) == 3, "Smem layout must be rank 3."); + static_assert( + cute::is_void_v, + "SM90 GMMA mainloops cannot have a non-void copy atom for smem sourced instructions."); + static_assert( + cute::is_void_v, + "SM90 GMMA mainloops cannot have a non-void copy atom for smem sourced instructions."); + + cute::Tensor sA = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_A.data()), + SmemLayoutA{}); // (BLK_M,BLK_K,PIPE) + cute::Tensor sB0 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B0.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + cute::Tensor sB1 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B1.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + cute::Tensor sB2 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B2.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + cute::Tensor sB3 = cute::make_tensor(cute::make_smem_ptr(shared_tensors.smem_B3.data()), + SmemLayoutB{}); // (BLK_N,BLK_K,PIPE) + + // + // Define C accumulators and A/B partitioning + // + + // Layout of warp group to thread mapping + + static_assert( + cute::stride<0>(typename TiledMma::ALayout{}) == 0 + and cute::stride<0>(typename TiledMma::BLayout{}) == 0 + and cute::size<0>(typename TiledMma::ALayout{}) == cutlass::NumThreadsPerWarpGroup + and cute::size<0>(typename TiledMma::BLayout{}) == cutlass::NumThreadsPerWarpGroup, + "Stride of the first mode must be 0 and the size of the mode must be " + "cutlass::NumThreadsPerWarpGroup"); + + constexpr int MmaWarpGroups = cute::size(TiledMma{}) / cutlass::NumThreadsPerWarpGroup; + cute::Layout warp_group_thread_layout = cute::make_layout( + cute::Int{}, cute::Int{}); + + int warp_group_idx = __shfl_sync(0xFFFFFFFF, thread_idx / cutlass::NumThreadsPerWarpGroup, 0); + + TiledMma tiled_mma; + auto thread_mma = tiled_mma.get_slice(warp_group_thread_layout(warp_group_idx)); + + cute::Tensor tCsA = thread_mma.partition_A(sA); // (MMA,MMA_M,MMA_K,PIPE) + cute::Tensor tCsB0 = thread_mma.partition_B(sB0); // (MMA,MMA_N,MMA_K,PIPE) + cute::Tensor tCsB1 = thread_mma.partition_B(sB1); // (MMA,MMA_N,MMA_K,PIPE) + cute::Tensor tCsB2 = thread_mma.partition_B(sB2); // (MMA,MMA_N,MMA_K,PIPE) + cute::Tensor tCsB3 = thread_mma.partition_B(sB3); // (MMA,MMA_N,MMA_K,PIPE) + + // Allocate "fragments/descriptors" + cute::Tensor tCrA = thread_mma.make_fragment_A(tCsA); // (MMA,MMA_M,MMA_K,PIPE) + cute::Tensor tCrB0 = thread_mma.make_fragment_B(tCsB0); // (MMA,MMA_N,MMA_K,PIPE) + cute::Tensor tCrB1 = thread_mma.make_fragment_B(tCsB1); // (MMA,MMA_N,MMA_K,PIPE) + cute::Tensor tCrB2 = thread_mma.make_fragment_B(tCsB2); // (MMA,MMA_N,MMA_K,PIPE) + cute::Tensor tCrB3 = thread_mma.make_fragment_B(tCsB3); // (MMA,MMA_N,MMA_K,PIPE) + + CUTE_STATIC_ASSERT_V(cute::size<1>(tCsA) == cute::size<1>(accum0)); // M + CUTE_STATIC_ASSERT_V(cute::size<1>(tCsB0) == cute::size<2>(accum0)); // N + CUTE_STATIC_ASSERT_V(cute::size<1>(tCsB1) == cute::size<2>(accum1)); // N + CUTE_STATIC_ASSERT_V(cute::size<1>(tCsB2) == cute::size<2>(accum2)); // N + CUTE_STATIC_ASSERT_V(cute::size<1>(tCsB3) == cute::size<2>(accum3)); // N + + CUTE_STATIC_ASSERT_V(cute::size<2>(tCsA) == cute::size<2>(tCsB0)); // K + CUTE_STATIC_ASSERT_V(cute::size<2>(tCsA) == cute::size<2>(tCsB1)); // K + CUTE_STATIC_ASSERT_V(cute::size<2>(tCsA) == cute::size<2>(tCsB2)); // K + CUTE_STATIC_ASSERT_V(cute::size<2>(tCsA) == cute::size<2>(tCsB3)); // K + + CUTE_STATIC_ASSERT_V(cute::size<3>(tCsA) == cute::size<3>(tCsB0)); // PIPE + CUTE_STATIC_ASSERT_V(cute::size<3>(tCsA) == cute::size<3>(tCsB1)); // PIPE + CUTE_STATIC_ASSERT_V(cute::size<3>(tCsA) == cute::size<3>(tCsB2)); // PIPE + CUTE_STATIC_ASSERT_V(cute::size<3>(tCsA) == cute::size<3>(tCsB3)); // PIPE + + CUTE_STATIC_ASSERT_V(cute::Int{} == cute::size<2>(sA)); // PIPE + CUTE_STATIC_ASSERT_V(cute::Int{} == cute::size<2>(sB0)); // PIPE + CUTE_STATIC_ASSERT_V(cute::Int{} == cute::size<2>(sB1)); // PIPE + CUTE_STATIC_ASSERT_V(cute::Int{} == cute::size<2>(sB2)); // PIPE + CUTE_STATIC_ASSERT_V(cute::Int{} == cute::size<2>(sB3)); // PIPE + + // + // PIPELINED MAIN LOOP + // + static_assert((0 <= K_PIPE_MMAS) && (K_PIPE_MMAS < K_PIPE_MAX), + "ERROR : Incorrect number of MMAs in flight"); + + // We release buffers to producer warps(dma load) with some mmas in flight + cutlass::PipelineState smem_pipe_release = smem_pipe_read; + + // Prologue GMMAs + int prologue_mma_count = min(K_PIPE_MMAS, k_tile_count); + assert(k_tile_count >= 1); + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::Zero; + cute::warpgroup_fence_operand(accum0); + cute::warpgroup_fence_operand(accum1); + cute::warpgroup_fence_operand(accum2); + cute::warpgroup_fence_operand(accum3); + { + // WAIT on smem_pipe_read until its data are available (phase bit flips from rdPhaseBit value) + auto barrier_token = pipeline.consumer_try_wait(smem_pipe_read); + pipeline.consumer_wait(smem_pipe_read, barrier_token); + + int read_stage = smem_pipe_read.index(); + cute::warpgroup_arrive(); + + // Unroll the K mode manually to set scale D to 1 (B0) + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::Zero; + CUTLASS_PRAGMA_UNROLL + for (int k_block = 0; k_block < cute::size<2>(tCrA); ++k_block) { + // (V,M,K) x (V,N,K) => (V,M,N) + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB0(cute::_, cute::_, k_block, read_stage), accum0); + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::One; + } + + // Unroll the K mode manually to set scale D to 1 (B1) + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::Zero; + CUTLASS_PRAGMA_UNROLL + for (int k_block = 0; k_block < cute::size<2>(tCrA); ++k_block) { + // (V,M,K) x (V,N,K) => (V,M,N) + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB1(cute::_, cute::_, k_block, read_stage), accum1); + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::One; + } + + // Unroll the K mode manually to set scale D to 1 (B2) + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::Zero; + CUTLASS_PRAGMA_UNROLL + for (int k_block = 0; k_block < cute::size<2>(tCrA); ++k_block) { + // (V,M,K) x (V,N,K) => (V,M,N) + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB2(cute::_, cute::_, k_block, read_stage), accum2); + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::One; + } + + // Unroll the K mode manually to set scale D to 1 (B3) + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::Zero; + CUTLASS_PRAGMA_UNROLL + for (int k_block = 0; k_block < cute::size<2>(tCrA); ++k_block) { + // (V,M,K) x (V,N,K) => (V,M,N) + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB3(cute::_, cute::_, k_block, read_stage), accum3); + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::One; + } + + cute::warpgroup_commit_batch(); + + ++smem_pipe_read; + } + + tiled_mma.accumulate_ = cute::GMMA::ScaleOut::One; + + cute::warpgroup_fence_operand(accum0); + cute::warpgroup_fence_operand(accum1); + cute::warpgroup_fence_operand(accum2); + cute::warpgroup_fence_operand(accum3); + + CUTLASS_PRAGMA_UNROLL + for (int k_tile_prologue = prologue_mma_count - 1; k_tile_prologue > 0; --k_tile_prologue) { + // WAIT on smem_pipe_read until its data are available (phase bit flips from rdPhaseBit value) + auto barrier_token = pipeline.consumer_try_wait(smem_pipe_read); + pipeline.consumer_wait(smem_pipe_read, barrier_token); + + int read_stage = smem_pipe_read.index(); + cute::warpgroup_arrive(); + // (V,M,K) x (V,N,K) => (V,M,N) + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, cute::_, read_stage), + tCrB0(cute::_, cute::_, cute::_, read_stage), accum0); + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, cute::_, read_stage), + tCrB1(cute::_, cute::_, cute::_, read_stage), accum1); + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, cute::_, read_stage), + tCrB2(cute::_, cute::_, cute::_, read_stage), accum2); + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, cute::_, read_stage), + tCrB3(cute::_, cute::_, cute::_, read_stage), accum3); + + cute::warpgroup_commit_batch(); + + ++smem_pipe_read; + } + + cute::warpgroup_fence_operand(accum0); + cute::warpgroup_fence_operand(accum1); + cute::warpgroup_fence_operand(accum2); + cute::warpgroup_fence_operand(accum3); + + // Mainloop GMMAs + k_tile_count -= prologue_mma_count; + + CUTLASS_PRAGMA_NO_UNROLL + for (; k_tile_count > 0; --k_tile_count) { + // WAIT on smem_pipe_read until its data are available (phase bit flips from rdPhaseBit value) + auto barrier_token = pipeline.consumer_try_wait(smem_pipe_read); + pipeline.consumer_wait(smem_pipe_read, barrier_token); + + // + // Compute on k_tile + // + + int read_stage = smem_pipe_read.index(); + cute::warpgroup_fence_operand(accum0); + cute::warpgroup_fence_operand(accum1); + cute::warpgroup_fence_operand(accum2); + cute::warpgroup_fence_operand(accum3); + + cute::warpgroup_arrive(); + // (V,M,K) x (V,N,K) => (V,M,N) + + CUTLASS_PRAGMA_UNROLL + for (int k_block = 0; k_block < cute::size<2>(tCrA); ++k_block) { + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB0(cute::_, cute::_, k_block, read_stage), accum0); + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB1(cute::_, cute::_, k_block, read_stage), accum1); + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB2(cute::_, cute::_, k_block, read_stage), accum2); + cute::gemm(tiled_mma, tCrA(cute::_, cute::_, k_block, read_stage), + tCrB3(cute::_, cute::_, k_block, read_stage), accum3); + } + cute::warpgroup_commit_batch(); + + /// Wait on the GMMA barrier for K_PIPE_MMAS (or fewer) outstanding to ensure smem_pipe_write is consumed + cute::warpgroup_wait(); + cute::warpgroup_fence_operand(accum0); + cute::warpgroup_fence_operand(accum1); + cute::warpgroup_fence_operand(accum2); + cute::warpgroup_fence_operand(accum3); + + // UNLOCK smem_pipe_release, done _computing_ on it + pipeline.consumer_release(smem_pipe_release); + + // Advance smem_pipe_read and smem_pipe_release + ++smem_pipe_read; + ++smem_pipe_release; + } + + cute::warpgroup_fence_operand(accum0); + cute::warpgroup_fence_operand(accum1); + cute::warpgroup_fence_operand(accum2); + cute::warpgroup_fence_operand(accum3); + } + + /// Perform a Consumer Epilogue to release all buffers + CUTLASS_DEVICE void mma_tail(MainloopPipeline pipeline, PipelineState smem_pipe_release, + int k_tile_count) + { + // Prologue GMMAs + int prologue_mma_count = min(K_PIPE_MMAS, k_tile_count); + k_tile_count -= prologue_mma_count; + + smem_pipe_release.advance(k_tile_count); + + // Wait on all GMMAs to complete + cute::warpgroup_wait<0>(); + + for (int count = 0; count < prologue_mma_count; ++count) { + pipeline.consumer_release( + smem_pipe_release); // UNLOCK smem_pipe_release, done _computing_ on it + ++smem_pipe_release; + } + } + + /// Issue Tma Descriptor Prefetch -- ideally from a single thread for best performance + CUTLASS_DEVICE + static void prefetch_tma_descriptors(Params const& mainloop_params) + { + cute::prefetch_tma_descriptor(mainloop_params.tma_load_a.get_tma_descriptor()); + cute::prefetch_tma_descriptor(mainloop_params.tma_load_b0.get_tma_descriptor()); + cute::prefetch_tma_descriptor(mainloop_params.tma_load_b1.get_tma_descriptor()); + cute::prefetch_tma_descriptor(mainloop_params.tma_load_b2.get_tma_descriptor()); + cute::prefetch_tma_descriptor(mainloop_params.tma_load_b3.get_tma_descriptor()); + } + + template + static constexpr Params to_underlying_arguments(ProblemShape const& problem_shape, + Arguments const& args, void* workspace) + { + (void)workspace; + + // Optionally append 1s until problem shape is rank-4 (MNKL), in case it is only rank-3 (MNK) + auto problem_shape_MNKL = cute::append<4>(problem_shape, 1); + auto [M, N, K, L] = problem_shape_MNKL; + + auto ptr_A = reinterpret_cast(args.ptr_A); + auto ptr_B0 = reinterpret_cast(args.ptr_B0); + auto ptr_B1 = reinterpret_cast(args.ptr_B1); + auto ptr_B2 = reinterpret_cast(args.ptr_B2); + auto ptr_B3 = reinterpret_cast(args.ptr_B3); + + cute::Tensor tensor_a = + cute::make_tensor(ptr_A, cute::make_layout(cute::make_shape(M, K, L), args.dA)); + cute::Tensor tensor_b0 = + cute::make_tensor(ptr_B0, cute::make_layout(cute::make_shape(N, K, L), args.dB)); + cute::Tensor tensor_b1 = + cute::make_tensor(ptr_B1, cute::make_layout(cute::make_shape(N, K, L), args.dB)); + cute::Tensor tensor_b2 = + cute::make_tensor(ptr_B2, cute::make_layout(cute::make_shape(N, K, L), args.dB)); + cute::Tensor tensor_b3 = + cute::make_tensor(ptr_B3, cute::make_layout(cute::make_shape(N, K, L), args.dB)); + + typename Params::TMA_A tma_load_a = cute::make_tma_copy_A_sm90( + GmemTiledCopyA{}, tensor_a, SmemLayoutA{}(cute::_, cute::_, cute::_0{}), TileShape{}, + ClusterShape{}); + typename Params::TMA_B tma_load_b0 = cute::make_tma_copy_B_sm90( + GmemTiledCopyB{}, tensor_b0, SmemLayoutB{}(cute::_, cute::_, cute::_0{}), TileShape{}, + ClusterShape{}); + typename Params::TMA_B tma_load_b1 = cute::make_tma_copy_B_sm90( + GmemTiledCopyB{}, tensor_b1, SmemLayoutB{}(cute::_, cute::_, cute::_0{}), TileShape{}, + ClusterShape{}); + typename Params::TMA_B tma_load_b2 = cute::make_tma_copy_B_sm90( + GmemTiledCopyB{}, tensor_b2, SmemLayoutB{}(cute::_, cute::_, cute::_0{}), TileShape{}, + ClusterShape{}); + typename Params::TMA_B tma_load_b3 = cute::make_tma_copy_B_sm90( + GmemTiledCopyB{}, tensor_b3, SmemLayoutB{}(cute::_, cute::_, cute::_0{}), TileShape{}, + ClusterShape{}); + uint32_t transaction_bytes_mk = TmaTransactionBytesMK; + uint32_t transaction_bytes_nk = TmaTransactionBytesNK; + uint32_t transaction_bytes = transaction_bytes_mk + transaction_bytes_nk * 4; + + return { tma_load_a, tma_load_b0, tma_load_b1, tma_load_b2, + tma_load_b3, transaction_bytes, transaction_bytes_mk, transaction_bytes_nk }; + } +}; diff --git a/src/layers/extensions/inference/cutlass/transposed_conv.cu b/src/layers/extensions/inference/cutlass/transposed_conv.cu new file mode 100644 index 0000000..49e523b --- /dev/null +++ b/src/layers/extensions/inference/cutlass/transposed_conv.cu @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "transposed_conv_kernel.h" +#include "../def_cutlass.h" + +const std::string HINT_MAP_TRANSPOSED_CONV_NAME = "HINT_MAP_TRANSPOSED_CONV"; +std::unordered_map HINT_MAP_TRANSPOSED_CONV = { +#if CURRENT_DEVICE_SM == 80 + { conv_key(80, 7, 4, 128, 128, 0, 0), 7 }, { conv_key(80, 7, 4, 128, 256, 0, 0), 7 }, + { conv_key(80, 13, 8, 128, 128, 0, 0), 7 }, { conv_key(80, 13, 8, 128, 256, 0, 0), 7 }, + { conv_key(80, 14, 8, 128, 128, 0, 0), 7 }, { conv_key(80, 14, 8, 256, 256, 0, 0), 8 }, + { conv_key(80, 20, 12, 128, 128, 0, 0), 7 }, { conv_key(80, 20, 12, 128, 256, 0, 0), 7 }, + { conv_key(80, 26, 15, 128, 256, 0, 0), 7 }, { conv_key(80, 26, 15, 256, 384, 0, 0), 13 }, + { conv_key(80, 26, 15, 256, 512, 0, 0), 13 }, { conv_key(80, 26, 16, 128, 128, 0, 0), 7 }, + { conv_key(80, 26, 16, 256, 256, 0, 0), 29 }, { conv_key(80, 30, 17, 128, 128, 0, 0), 7 }, + { conv_key(80, 30, 17, 128, 256, 0, 0), 29 }, { conv_key(80, 40, 24, 128, 128, 0, 0), 7 }, + { conv_key(80, 40, 24, 256, 256, 0, 0), 13 }, { conv_key(80, 52, 30, 128, 256, 0, 0), 13 }, + { conv_key(80, 52, 30, 256, 384, 0, 0), 10 }, { conv_key(80, 52, 30, 256, 512, 0, 0), 10 }, + { conv_key(80, 60, 34, 128, 128, 0, 0), 5 }, { conv_key(80, 60, 34, 128, 256, 0, 0), 10 }, + { conv_key(80, 60, 34, 256, 256, 0, 0), 10 }, { conv_key(80, 80, 45, 128, 256, 0, 0), 13 }, + { conv_key(80, 80, 45, 256, 384, 0, 0), 14 }, { conv_key(80, 80, 45, 256, 512, 0, 0), 13 }, + { conv_key(80, 120, 68, 128, 128, 0, 0), 14 }, { conv_key(80, 120, 68, 128, 256, 0, 0), 14 }, + { conv_key(80, 120, 68, 256, 256, 0, 0), 14 }, { conv_key(80, 120, 68, 256, 384, 0, 0), 14 }, + { conv_key(80, 120, 68, 256, 512, 0, 0), 13 }, { conv_key(80, 240, 135, 128, 256, 0, 0), 13 }, + { conv_key(80, 240, 135, 256, 384, 0, 0), 14 }, { conv_key(80, 240, 135, 256, 512, 0, 0), 13 }, +#elif CURRENT_DEVICE_SM == 89 + { conv_key(89, 7, 4, 128, 128, 0, 0), 7 }, { conv_key(89, 7, 4, 128, 256, 0, 0), 7 }, + { conv_key(89, 13, 8, 128, 128, 0, 0), 7 }, { conv_key(89, 13, 8, 128, 256, 0, 0), 7 }, + { conv_key(89, 14, 8, 128, 128, 0, 0), 7 }, { conv_key(89, 14, 8, 256, 256, 0, 0), 8 }, + { conv_key(89, 20, 12, 128, 128, 0, 0), 7 }, { conv_key(89, 20, 12, 128, 256, 0, 0), 7 }, + { conv_key(89, 26, 15, 128, 256, 0, 0), 8 }, { conv_key(89, 26, 15, 256, 384, 0, 0), 18 }, + { conv_key(89, 26, 15, 256, 512, 0, 0), 18 }, { conv_key(89, 26, 16, 128, 128, 0, 0), 7 }, + { conv_key(89, 26, 16, 256, 256, 0, 0), 8 }, { conv_key(89, 30, 17, 128, 128, 0, 0), 19 }, + { conv_key(89, 30, 17, 128, 256, 0, 0), 19 }, { conv_key(89, 40, 24, 128, 128, 0, 0), 8 }, + { conv_key(89, 40, 24, 256, 256, 0, 0), 18 }, { conv_key(89, 52, 30, 128, 256, 0, 0), 14 }, + { conv_key(89, 52, 30, 256, 384, 0, 0), 5 }, { conv_key(89, 52, 30, 256, 512, 0, 0), 2 }, + { conv_key(89, 60, 34, 128, 128, 0, 0), 7 }, { conv_key(89, 60, 34, 128, 256, 0, 0), 14 }, + { conv_key(89, 60, 34, 256, 256, 0, 0), 14 }, { conv_key(89, 80, 45, 128, 256, 0, 0), 14 }, + { conv_key(89, 80, 45, 256, 384, 0, 0), 14 }, { conv_key(89, 80, 45, 256, 512, 0, 0), 14 }, + { conv_key(89, 120, 68, 128, 128, 0, 0), 14 }, { conv_key(89, 120, 68, 128, 256, 0, 0), 14 }, + { conv_key(89, 120, 68, 256, 256, 0, 0), 14 }, { conv_key(89, 120, 68, 256, 384, 0, 0), 14 }, + { conv_key(89, 120, 68, 256, 512, 0, 0), 14 }, { conv_key(89, 240, 135, 128, 256, 0, 0), 0 }, + { conv_key(89, 240, 135, 256, 384, 0, 0), 14 }, { conv_key(89, 240, 135, 256, 512, 0, 0), 14 }, +#elif CURRENT_DEVICE_SM == 90 + { conv_key(90, 7, 4, 128, 128, 0, 0), 7 }, { conv_key(90, 7, 4, 128, 256, 0, 0), 7 }, + { conv_key(90, 13, 8, 128, 128, 0, 0), 7 }, { conv_key(90, 13, 8, 128, 256, 0, 0), 7 }, + { conv_key(90, 14, 8, 128, 128, 0, 0), 7 }, { conv_key(90, 14, 8, 256, 256, 0, 0), 8 }, + { conv_key(90, 20, 12, 128, 128, 0, 0), 7 }, { conv_key(90, 20, 12, 128, 256, 0, 0), 7 }, + { conv_key(90, 26, 15, 128, 256, 0, 0), 7 }, { conv_key(90, 26, 15, 256, 384, 0, 0), 29 }, + { conv_key(90, 26, 15, 256, 512, 0, 0), 29 }, { conv_key(90, 26, 16, 128, 128, 0, 0), 7 }, + { conv_key(90, 26, 16, 256, 256, 0, 0), 8 }, { conv_key(90, 30, 17, 128, 128, 0, 0), 7 }, + { conv_key(90, 30, 17, 128, 256, 0, 0), 7 }, { conv_key(90, 40, 24, 128, 128, 0, 0), 7 }, + { conv_key(90, 40, 24, 256, 256, 0, 0), 29 }, { conv_key(90, 52, 30, 128, 256, 0, 0), 13 }, + { conv_key(90, 52, 30, 256, 384, 0, 0), 10 }, { conv_key(90, 52, 30, 256, 512, 0, 0), 13 }, + { conv_key(90, 60, 34, 128, 128, 0, 0), 5 }, { conv_key(90, 60, 34, 128, 256, 0, 0), 26 }, + { conv_key(90, 60, 34, 256, 256, 0, 0), 26 }, { conv_key(90, 80, 45, 128, 256, 0, 0), 13 }, + { conv_key(90, 80, 45, 256, 384, 0, 0), 14 }, { conv_key(90, 80, 45, 256, 512, 0, 0), 13 }, + { conv_key(90, 120, 68, 128, 128, 0, 0), 14 }, { conv_key(90, 120, 68, 128, 256, 0, 0), 13 }, + { conv_key(90, 120, 68, 256, 256, 0, 0), 13 }, { conv_key(90, 120, 68, 256, 384, 0, 0), 14 }, + { conv_key(90, 120, 68, 256, 512, 0, 0), 13 }, { conv_key(90, 240, 135, 128, 256, 0, 0), 13 }, + { conv_key(90, 240, 135, 256, 384, 0, 0), 27 }, { conv_key(90, 240, 135, 256, 512, 0, 0), 10 }, +#elif CURRENT_DEVICE_SM == 100 + { conv_key(100, 7, 4, 128, 128, 0, 0), 6 }, + { conv_key(100, 7, 4, 128, 256, 0, 0), 5 }, + { conv_key(100, 13, 8, 128, 128, 0, 0), 7 }, + { conv_key(100, 13, 8, 128, 256, 0, 0), 7 }, + { conv_key(100, 14, 8, 128, 128, 0, 0), 7 }, + { conv_key(100, 14, 8, 256, 256, 0, 0), 8 }, + { conv_key(100, 20, 12, 128, 128, 0, 0), 7 }, + { conv_key(100, 20, 12, 128, 256, 0, 0), 5 }, + { conv_key(100, 26, 15, 128, 256, 0, 0), 7 }, + { conv_key(100, 26, 15, 256, 384, 0, 0), 29 }, + { conv_key(100, 26, 15, 256, 512, 0, 0), 29 }, + { conv_key(100, 26, 16, 128, 128, 0, 0), 5 }, + { conv_key(100, 26, 16, 256, 256, 0, 0), 8 }, + { conv_key(100, 30, 17, 128, 128, 0, 0), 7 }, + { conv_key(100, 30, 17, 128, 256, 0, 0), 7 }, + { conv_key(100, 40, 24, 128, 128, 0, 0), 7 }, + { conv_key(100, 40, 24, 256, 256, 0, 0), 29 }, + { conv_key(100, 52, 30, 128, 256, 0, 0), 13 }, + { conv_key(100, 52, 30, 256, 384, 0, 0), 10 }, + { conv_key(100, 52, 30, 256, 512, 0, 0), 10 }, + { conv_key(100, 60, 34, 128, 128, 0, 0), 7 }, + { conv_key(100, 60, 34, 128, 256, 0, 0), 13 }, + { conv_key(100, 60, 34, 256, 256, 0, 0), 13 }, + { conv_key(100, 80, 45, 128, 256, 0, 0), 13 }, + { conv_key(100, 80, 45, 256, 384, 0, 0), 14 }, + { conv_key(100, 80, 45, 256, 512, 0, 0), 13 }, + { conv_key(100, 120, 68, 128, 128, 0, 0), 14 }, + { conv_key(100, 120, 68, 128, 256, 0, 0), 13 }, + { conv_key(100, 120, 68, 256, 256, 0, 0), 13 }, + { conv_key(100, 120, 68, 256, 384, 0, 0), 14 }, + { conv_key(100, 120, 68, 256, 512, 0, 0), 13 }, + { conv_key(100, 240, 135, 128, 256, 0, 0), 13 }, + { conv_key(100, 240, 135, 256, 384, 0, 0), 14 }, + { conv_key(100, 240, 135, 256, 512, 0, 0), 13 }, +#endif +}; + +at::Tensor transposed_conv(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const int stride, at::Tensor& out_buf) +{ + const int kernel = weight.size(2); + if (sm < 75) { + return at::conv_transpose2d(feature, weight, at::nullopt, stride); + } + auto launch_cutlass = [&](auto sm_v) { + using sm_t = decltype(sm_v); + return transposed_conv_generic_cutlass(out_buf, feature, weight, stride); + }; + const int H = feature.size(2); + const int W = feature.size(3); + const int C2 = weight.size(0); + const int C1 = weight.size(1); + assert(kernel == stride && kernel == 2); + return launch_cutlass_helper( + sm, launch_cutlass, HINT_MAP_TRANSPOSED_CONV, HINT_MAP_TRANSPOSED_CONV_NAME, C2, C1, H, W); +} diff --git a/src/layers/extensions/inference/cutlass/transposed_conv_kernel.h b/src/layers/extensions/inference/cutlass/transposed_conv_kernel.h new file mode 100644 index 0000000..f7eded5 --- /dev/null +++ b/src/layers/extensions/inference/cutlass/transposed_conv_kernel.h @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +#include +#include +#include +#include +// clang-format on + +#include "cutlass_epilogue.h" +#include "cutlass_kernel.h" +#include "../common_cu.h" +#include "../cutlass_helper_implicit_gemm.h" +#include "../def_cutlass.h" + +template +at::Tensor transposed_conv_generic_cutlass(at::Tensor& out_buf, const at::Tensor& feature, + const at::Tensor& weight, const int stride) +{ + using EpilogueOp = cutlass::epilogue::thread::LinearCombination< + cutlass::half_t, 128 / cutlass::sizeof_bits_v, cutlass::half_t, + cutlass::half_t, cutlass::epilogue::thread::ScaleType::Nothing>; + + using Conv2dDgradKernel = typename CustomDefaultConv2dDgrad< + cutlass::half_t, cutlass::layout::TensorNHWC, cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, cutlass::half_t, cutlass::arch::OpClassTensorOp, + typename Sm::SmArch, typename Sm::ShapeThreadBlock, typename Sm::ShapeWarp, typename Sm::ShapeOp, + EpilogueOp, cutlass::conv::threadblock::StridedDgradIdentityThreadblockSwizzle<8>, Sm::Stages, + cutlass::arch::OpMultiplyAdd, cutlass::conv::IteratorAlgorithm::kOptimized>::Kernel; + + using ImplicitGemm = CustomImplicitGemmConvolution; + + const int B = feature.size(0); + const int Cin = feature.size(1); + const int H = feature.size(2); + const int W = feature.size(3); + const int Cin_ = weight.size(0); + const int Cout = weight.size(1); + const int kernel = weight.size(2); + const int kernel_ = weight.size(3); + assert(Cin == Cin_ && kernel == kernel_ && kernel == stride); + + cutlass::conv::Conv2dProblemSize problem_size({ B, H * stride, W * stride, Cout }, // out + { Cin, kernel, kernel, Cout }, // kernel + { 0, 0, 0, 0 }, // pad + { stride, stride }, // stride + { 1, 1 }, // dilation + { B, H, W, Cin }, // input + cutlass::conv::Mode::kCrossCorrelation, + 1 // split_k_slices + ); + + cutlass::TensorRef d_feature( + static_cast(feature.data_ptr()), + cutlass::make_Coord(feature.stride(3), feature.stride(2), feature.stride(0))); + cutlass::TensorRef d_weight( + static_cast(weight.data_ptr()), + cutlass::make_Coord(weight.stride(3), weight.stride(2), weight.stride(0))); + cutlass::TensorRef d_out( + static_cast(out_buf.data_ptr()), + cutlass::make_Coord(out_buf.stride(3), out_buf.stride(2), out_buf.stride(0))); + + typename ImplicitGemm::Arguments args(problem_size, d_feature, d_weight, d_out, d_out, {}); + + ImplicitGemm implicit_gemm_op; + cutlass::Status status = implicit_gemm_op.can_implement(args); + if (status != cutlass::Status::kSuccess) { + std::cerr << "Failed to configure convolution operation." << std::endl; + return at::Tensor(); + } + + auto stream = at::cuda::getCurrentCUDAStream(); + status = implicit_gemm_op(args, nullptr, stream); + if (status != cutlass::Status::kSuccess) { + std::cerr << "Failed to run convolution operation." << std::endl; + return at::Tensor(); + } + + return out_buf; +} diff --git a/src/layers/extensions/inference/cutlass_helper_gemm.h b/src/layers/extensions/inference/cutlass_helper_gemm.h new file mode 100644 index 0000000..d19eaa5 --- /dev/null +++ b/src/layers/extensions/inference/cutlass_helper_gemm.h @@ -0,0 +1,450 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +// clang-format on + +/** + * These 3 classes/structs are rewritten: + * 1. cutlass::gemm::kernel::GemmWithFusedEpilogue -> CustomGemmWithFusedEpilogue + * 2. cutlass::gemm::kernel::DefaultGemmWithBroadcast -> CustomDefaultGemmWithBroadcast + * 3. cutlass::gemm::device::GemmUniversalWithBroadcast -> CustomGemmUniversalWithBroadcast + */ + +/// Original file: cutlass/gemm/kernel/gemm_with_fused_epilogue.h +/// to add PDL sync points +/// depending on IsSingleSource, there are 2 specializations +template +struct CustomGemmWithFusedEpilogue; + +template +struct CustomGemmWithFusedEpilogue { + using Base = + cutlass::gemm::kernel::GemmWithFusedEpilogue; + using Mma = typename Base::Mma; + using Epilogue = typename Base::Epilogue; + using EpilogueOutputOp = typename Base::EpilogueOutputOp; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + using Params = typename Base::Params; + using SharedStorage = typename Base::SharedStorage; + using Arguments = typename Base::Arguments; + + using ElementA = typename Base::ElementA; + using LayoutA = typename Base::LayoutA; + using ElementB = typename Base::ElementB; + using LayoutB = typename Base::LayoutB; + using ElementC = typename Base::ElementC; + using LayoutC = typename Base::LayoutC; + + static cutlass::ComplexTransform const kTransformA = Base::kTransformA; + static cutlass::ComplexTransform const kTransformB = Base::kTransformB; + static int const kThreadCount = Base::kThreadCount; + using Operator = typename Base::Operator; + + /// Executes one GEMM + CUTLASS_DEVICE + void operator()(Params const& params, SharedStorage& shared_storage) + { + // Compute threadblock location + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord threadblock_tile_offset = + threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // Early exit if CTA is out of range + if (params.grid_tiled_shape.m() <= threadblock_tile_offset.m() + || params.grid_tiled_shape.n() <= threadblock_tile_offset.n()) { + cudaGDC(); + return; + } + + int offset_k = 0; + int problem_size_k = params.problem_size.k(); + + ElementA* ptr_A = static_cast(params.ptr_A); + ElementB* ptr_B = static_cast(params.ptr_B); + + // Compute initial location in logical coordinates + cutlass::MatrixCoord tb_offset_A{ + threadblock_tile_offset.m() * Mma::Shape::kM, + offset_k, + }; + + cutlass::MatrixCoord tb_offset_B{ offset_k, threadblock_tile_offset.n() * Mma::Shape::kN }; + + // Compute position within threadblock + int thread_idx = threadIdx.x; + + // Construct iterators to A and B operands + typename Mma::IteratorA iterator_A(params.params_A, ptr_A, + { params.problem_size.m(), problem_size_k }, thread_idx, + tb_offset_A); + + typename Mma::IteratorB iterator_B(params.params_B, ptr_B, + { problem_size_k, params.problem_size.n() }, thread_idx, + tb_offset_B); + + // Broadcast the warp_id computed by lane 0 to ensure dependent code + // is compiled as warp-uniform. + int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + + int lane_idx = threadIdx.x % 32; + + // + // Main loop + // + + // Construct thread-scoped matrix multiply + Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx); + + typename Mma::FragmentC accumulators; + + accumulators.clear(); + + // Compute threadblock-scoped matrix multiply-add + int gemm_k_iterations = (problem_size_k - offset_k + Mma::Shape::kK - 1) / Mma::Shape::kK; + + // Compute threadblock-scoped matrix multiply-add + cudaGDC(); + mma(gemm_k_iterations, accumulators, iterator_A, iterator_B, accumulators); + + // + // Epilogue + // + + EpilogueOutputOp output_op(params.output_op); + + // + // Masked tile iterators constructed from members + // + + threadblock_tile_offset = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // assume identity swizzle + cutlass::MatrixCoord threadblock_offset(threadblock_tile_offset.m() * Mma::Shape::kM, + threadblock_tile_offset.n() * Mma::Shape::kN); + + int block_idx = + threadblock_tile_offset.m() + threadblock_tile_offset.n() * params.grid_tiled_shape.m(); + + ElementC* ptr_C1 = static_cast(params.ptr_C1); + ElementC* ptr_C2 = static_cast(params.ptr_C2); + ElementC* ptr_D = static_cast(params.ptr_D); + typename Epilogue::ElementTensor* ptr_Tensor = + static_cast(params.ptr_Tensor); + + // Define the reduction output pointer and move to the appropriate place + typename Epilogue::ElementVector* ptr_Vector = + static_cast(params.ptr_Vector); + + // Tile iterators loading from source tensors. + typename Epilogue::OutputTileIterator iterator_C1( + params.params_C1, ptr_C1, params.problem_size.mn(), thread_idx, threadblock_offset); + + typename Epilogue::OutputTileIterator iterator_C2( + params.params_C2, ptr_C2, params.problem_size.mn(), thread_idx, threadblock_offset); + + // Tile iterator writing to destination tensor. + typename Epilogue::OutputTileIterator iterator_D( + params.params_D, ptr_D, params.problem_size.mn(), thread_idx, threadblock_offset); + + // Additional tensor to load from + typename Epilogue::TensorTileIterator tensor_iterator(params.params_Tensor, + // Only the final block outputs Tensor + ptr_Tensor, params.problem_size.mn(), + thread_idx, threadblock_offset); + + // Construct the epilogue + Epilogue epilogue(shared_storage.epilogue, thread_idx, warp_idx, lane_idx); + + // Move to appropriate location for this output tile + if (ptr_Vector) { + ptr_Vector += threadblock_offset.column() + threadblock_tile_offset.m() * params.ldr; + } + + // Execute the epilogue operator to update the destination tensor. + epilogue(output_op, ptr_Vector, iterator_D, accumulators, iterator_C1, iterator_C2, + tensor_iterator, params.problem_size.mn(), threadblock_offset); + } + + // Factory invocation + CUTLASS_DEVICE + static void invoke(Params const& params, SharedStorage& shared_storage) + { + CustomGemmWithFusedEpilogue op; + op(params, shared_storage); + } + + static cutlass::Status can_implement(Arguments const& args) + { + return Base::can_implement(args); + } +}; + +template +struct CustomGemmWithFusedEpilogue { + using Base = + cutlass::gemm::kernel::GemmWithFusedEpilogue; + using Mma = typename Base::Mma; + using Epilogue = typename Base::Epilogue; + using EpilogueOutputOp = typename Base::EpilogueOutputOp; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + using Params = typename Base::Params; + using SharedStorage = typename Base::SharedStorage; + using Arguments = typename Base::Arguments; + + using ElementA = typename Base::ElementA; + using LayoutA = typename Base::LayoutA; + using ElementB = typename Base::ElementB; + using LayoutB = typename Base::LayoutB; + using ElementC = typename Base::ElementC; + using LayoutC = typename Base::LayoutC; + + static cutlass::ComplexTransform const kTransformA = Base::kTransformA; + static cutlass::ComplexTransform const kTransformB = Base::kTransformB; + static int const kThreadCount = Base::kThreadCount; + using Operator = typename Base::Operator; + + /// Executes one GEMM + CUTLASS_DEVICE + void operator()(Params const& params, SharedStorage& shared_storage) + { + // Compute threadblock location + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord threadblock_tile_offset = + threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // Early exit if CTA is out of range + if (params.grid_tiled_shape.m() <= threadblock_tile_offset.m() + || params.grid_tiled_shape.n() <= threadblock_tile_offset.n()) { + cudaGDC(); + return; + } + + int offset_k = 0; + int problem_size_k = params.problem_size.k(); + + ElementA* ptr_A = static_cast(params.ptr_A); + ElementB* ptr_B = static_cast(params.ptr_B); + + // Compute initial location in logical coordinates + cutlass::MatrixCoord tb_offset_A{ + threadblock_tile_offset.m() * Mma::Shape::kM, + offset_k, + }; + + cutlass::MatrixCoord tb_offset_B{ offset_k, threadblock_tile_offset.n() * Mma::Shape::kN }; + + // Compute position within threadblock + int thread_idx = threadIdx.x; + + // Construct iterators to A and B operands + typename Mma::IteratorA iterator_A(params.params_A, ptr_A, + { params.problem_size.m(), problem_size_k }, thread_idx, + tb_offset_A); + + typename Mma::IteratorB iterator_B(params.params_B, ptr_B, + { problem_size_k, params.problem_size.n() }, thread_idx, + tb_offset_B); + + // Broadcast the warp_id computed by lane 0 to ensure dependent code + // is compiled as warp-uniform. + int warp_idx = cutlass::canonical_warp_idx_sync(); + + int lane_idx = threadIdx.x % 32; + + // + // Main loop + // + + // Construct thread-scoped matrix multiply + Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx); + + typename Mma::FragmentC accumulators; + + accumulators.clear(); + + // Compute threadblock-scoped matrix multiply-add + int gemm_k_iterations = (problem_size_k - offset_k + Mma::Shape::kK - 1) / Mma::Shape::kK; + + // Compute threadblock-scoped matrix multiply-add + cudaGDC(); + mma(gemm_k_iterations, accumulators, iterator_A, iterator_B, accumulators); + + // + // Epilogue + // + + EpilogueOutputOp output_op(params.output_op); + + // + // Masked tile iterators constructed from members + // + + threadblock_tile_offset = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // assume identity swizzle + cutlass::MatrixCoord threadblock_offset(threadblock_tile_offset.m() * Mma::Shape::kM, + threadblock_tile_offset.n() * Mma::Shape::kN); + + int block_idx = + threadblock_tile_offset.m() + threadblock_tile_offset.n() * params.grid_tiled_shape.m(); + + ElementC* ptr_C = static_cast(params.ptr_C); + ElementC* ptr_D = static_cast(params.ptr_D); + typename Epilogue::ElementTensor* ptr_Tensor = + static_cast(params.ptr_Tensor); + + // Define the reduction output pointer and move to the appropriate place + typename Epilogue::ElementVector* ptr_Vector = + static_cast(params.ptr_Vector); + + // Tile iterators loading from source tensors. + typename Epilogue::OutputTileIterator iterator_C( + params.params_C, ptr_C, params.problem_size.mn(), thread_idx, threadblock_offset); + + // Tile iterator writing to destination tensor. + typename Epilogue::OutputTileIterator iterator_D( + params.params_D, ptr_D, params.problem_size.mn(), thread_idx, threadblock_offset); + + // Additional tensor to load from + typename Epilogue::TensorTileIterator tensor_iterator(params.params_Tensor, + // Only the final block outputs Tensor + ptr_Tensor, params.problem_size.mn(), + thread_idx, threadblock_offset); + + // Construct the epilogue + Epilogue epilogue(shared_storage.epilogue, thread_idx, warp_idx, lane_idx); + + // Move to appropriate location for this output tile + if (ptr_Vector) { + ptr_Vector += threadblock_offset.column() + threadblock_tile_offset.m() * params.ldr; + } + + // Execute the epilogue operator to update the destination tensor. + epilogue(output_op, ptr_Vector, iterator_D, accumulators, iterator_C, tensor_iterator, + params.problem_size.mn(), threadblock_offset); + } + + // Factory invocation + CUTLASS_DEVICE + static void invoke(Params const& params, SharedStorage& shared_storage) + { + CustomGemmWithFusedEpilogue op; + op(params, shared_storage); + } + + static cutlass::Status can_implement(Arguments const& args) + { + return Base::can_implement(args); + } +}; + +/// Original file: cutlass/gemm/kernel/default_gemm_with_broadcast.h +/// to invoke CustomGemmWithFusedEpilogue +template +struct CustomDefaultGemmWithBroadcast { + using Base = typename cutlass::gemm::kernel::DefaultGemmWithBroadcast< + ElementA_, LayoutA_, TransformA, AlignmentA, ElementB_, LayoutB_, TransformB, AlignmentB, + ElementC_, LayoutC_, ElementAccumulator_, OperatorClass_, ArchTag_, ThreadblockShape_, + WarpShape_, InstructionShape_, EpilogueOutputOp_, ThreadblockSwizzle_, Stages, Operator_>; + using GemmKernel = + CustomGemmWithFusedEpilogue; +}; + +/// Original file: cutlass/gemm/device/gemm_universal_with_broadcast.h +/// to add "cudaLaunchKernelEx" to run() +template ::kAlignmentA, + int AlignmentB = cutlass::gemm::device::DefaultGemmConfiguration< + OperatorClass_, ArchTag_, ElementA_, ElementB_, ElementC_, ElementAccumulator_>::kAlignmentB, + typename Operator_ = typename cutlass::gemm::device::DefaultGemmConfiguration< + OperatorClass_, ArchTag_, ElementA_, ElementB_, ElementC_, ElementAccumulator_>::Operator, + cutlass::ComplexTransform TransformA = cutlass::ComplexTransform::kNone, + cutlass::ComplexTransform TransformB = cutlass::ComplexTransform::kNone> +class CustomGemmUniversalWithBroadcast + : public cutlass::gemm::device::GemmUniversalBase::GemmKernel> { +public: + using Base = cutlass::gemm::device::GemmUniversalBase::GemmKernel>; + + using Arguments = typename Base::Arguments; + using GemmKernel = typename Base::GemmKernel; + + static constexpr size_t kSharedStorageSize = Base::kSharedStorageSize; + + cutlass::Status run(cudaStream_t stream = nullptr) + { + CUTLASS_TRACE_HOST("GemmUniversalBase::run()"); + + // Configure grid and block dimensions + dim3 block(GemmKernel::kThreadCount, 1, 1); + dim3 grid = this->params_.get_grid_dims(); + + // Launch kernel + CUTLASS_TRACE_HOST( + " " + "grid: (" + << grid + << "), " + "block: (" + << block + << "), " + "SMEM: (" + << Base::kSharedStorageSize << ")"); + + cutlass::arch::synclog_setup(); + + cudaLaunchConfig_t config; + config.gridDim = grid; + config.blockDim = block; + config.dynamicSmemBytes = kSharedStorageSize; + config.stream = stream; + auto attr = get_cuda_launch_attribute(); + config.attrs = &attr; + config.numAttrs = 1; + + cudaLaunchKernelEx(&config, &cutlass::Kernel2, this->params_); + + // Query for errors + cudaError_t result = cudaGetLastError(); + if (result != cudaSuccess) { + CUTLASS_TRACE_HOST(" grid launch failed with error " << cudaGetErrorString(result)); + return cutlass::Status::kErrorInternal; + } + + return cutlass::Status::kSuccess; + } + + cutlass::Status operator()(Arguments const& args, void* workspace = nullptr, + cudaStream_t stream = nullptr) + { + cutlass::Status status = this->initialize(args, workspace, stream); + + if (status == cutlass::Status::kSuccess) { + status = run(stream); + } + + return status; + } +}; diff --git a/src/layers/extensions/inference/cutlass_helper_implicit_gemm.h b/src/layers/extensions/inference/cutlass_helper_implicit_gemm.h new file mode 100644 index 0000000..8ed4dc5 --- /dev/null +++ b/src/layers/extensions/inference/cutlass_helper_implicit_gemm.h @@ -0,0 +1,503 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// clang-format off +#include +#include +#include +#include +#include +#include +#include +// clang-format on + +/** + * These 5 classes/structs are rewritten: + * 1. cutlass::conv::kernel::ImplicitGemmConvolutionWithFusedEpilogue -> CustomImplicitGemmConvolutionWithFusedEpilogue + * 2. cutlass::conv::kernel::DefaultConv2dFpropWithBroadcast -> CustomDefaultConv2dFpropWithBroadcast + * 3. cutlass::conv::kernel::ImplicitGemmConvolutionStridedDgrad -> CustomImplicitGemmConvolutionStridedDgrad + * 4. cutlass::conv::kernel::DefaultConv2dDgrad -> CustomDefaultConv2dDgrad + * 5. cutlass::conv::device::ImplicitGemmConvolution -> CustomImplicitGemmConvolution + */ + +/// Original file: cutlass/conv/kernel/implicit_gemm_convolution_with_fused_epilogue.h +/// to add PDL sync points +template +struct CustomImplicitGemmConvolutionWithFusedEpilogue { + using Base = cutlass::conv::kernel::ImplicitGemmConvolutionWithFusedEpilogue< + Mma_, Epilogue_, ThreadblockSwizzle_, ConvOperator, ConvProblemSize_>; + using ElementA = typename Base::ElementA; + using LayoutA = typename Base::LayoutA; + using ElementB = typename Base::ElementB; + using LayoutB = typename Base::LayoutB; + using ElementC = typename Base::ElementC; + using LayoutC = typename Base::LayoutC; + using ElementAccumulator = typename Base::ElementAccumulator; + using ElementCompute = typename Base::ElementCompute; + using OperatorClass = typename Base::OperatorClass; + using ArchTag = typename Base::ArchTag; + using ThreadblockShape = typename Base::ThreadblockShape; + using WarpShape = typename Base::WarpShape; + using InstructionShape = typename Base::InstructionShape; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + using EpilogueOutputOp = typename Base::EpilogueOutputOp; + static int const kStages = Base::kStages; + static int const kConvDim = Base::kConvDim; + using WarpMmaOperator = typename Base::WarpMmaOperator; + using ArchMmaOperator = typename Base::ArchMmaOperator; + using MathOperator = typename Base::MathOperator; + + static cutlass::conv::Operator const kConvolutionalOperator = Base::kConvolutionalOperator; + static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Base::kIteratorAlgorithm; + static cutlass::conv::StrideSupport const kStrideSupport = Base::kStrideSupport; + static cutlass::conv::GroupMode const kGroupMode = Base::kGroupMode; + + using Arguments = typename Base::Arguments; + using Mma = typename Base::Mma; + using Epilogue = typename Base::Epilogue; + using Params = typename Base::Params; + using SharedStorage = typename Base::SharedStorage; + + using ConvOutputIteratorParameter = typename Base::ConvOutputIteratorParameter; + + /// Executes one ImplicitGEMM + CUTLASS_DEVICE + void operator()(Params const& params, SharedStorage& shared_storage) + { + // Compute threadblock location + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord threadblock_tile_idx = + threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // Early exit if CTA is out of range + if (params.grid_tiled_shape.m() <= threadblock_tile_idx.m() + || params.grid_tiled_shape.n() <= threadblock_tile_idx.n()) { + cudaGDC(); + return; + } + + // Compute position within threadblock + int thread_idx = threadIdx.x; + + // Construct iterators to A and B operands + typename Mma::IteratorA iterator_A( + params.iterator_A, params.problem_size, params.ptr_A, thread_idx, + cutlass::MatrixCoord(threadblock_tile_idx.m() * Mma::Shape::kM, + threadblock_tile_idx.k() * Mma::Shape::kK)); + + typename Mma::IteratorB iterator_B( + params.iterator_B, params.problem_size, params.ptr_B, thread_idx, + cutlass::MatrixCoord(threadblock_tile_idx.k() * Mma::Shape::kK, + threadblock_tile_idx.n() * Mma::Shape::kN)); + + // Broadcast the warp_id computed by lane 0 to ensure dependent code + // is compiled as warp-uniform. + int warp_idx = cutlass::canonical_warp_idx_sync(); + int lane_idx = threadIdx.x % 32; + + // + // Main loop + // + + // Construct thread-scoped matrix multiply + Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx); + + typename Mma::FragmentC accumulators; + + accumulators.clear(); + + // Compute threadblock-scoped matrix multiply-add + cudaGDC(); + mma(params.gemm_k_iterations, accumulators, iterator_A, iterator_B, accumulators); + + // + // Epilogue + // + + EpilogueOutputOp output_op(params.output_op); + + // Compute logical position within grid + threadblock_tile_idx = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + cutlass::MatrixCoord threadblock_offset(threadblock_tile_idx.m() * Mma::Shape::kM, + threadblock_tile_idx.n() * Mma::Shape::kN); + + // Tile iterator writing to destination tensor + typename Epilogue::OutputTileIterator iterator_D( + params.iterator_D, params.ptr_D, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, threadblock_offset); + + // Tile iterator reading from source accumulator tensor + typename Epilogue::OutputTileIterator iterator_C( + params.iterator_C, params.ptr_C, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, threadblock_offset); + + typename Epilogue::ElementTensor* ptr_Tensor = + static_cast(params.ptr_Tensor); + + // Define the reduction output pointer and move to the appropriate place + typename Epilogue::ElementVector* ptr_Vector = + static_cast(params.ptr_Vector); + + // Additional tensor to load from + typename Epilogue::TensorTileIterator tensor_iterator( + params.params_Tensor, ptr_Tensor, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, threadblock_offset); + + // Construct the epilogue + Epilogue epilogue(shared_storage.epilogue, thread_idx, warp_idx, lane_idx); + + // Move to appropriate location for this output tile + if (ptr_Vector) { + ptr_Vector += threadblock_offset.column() + threadblock_tile_idx.m() * params.ldr; + } + + // Execute the epilogue operator to update the destination tensor. + epilogue(output_op, ptr_Vector, iterator_D, accumulators, iterator_C, tensor_iterator, + ConvOutputIteratorParameter::extent(params.problem_size), threadblock_offset); + } +}; + +/// Original file: cutlass/conv/kernel/default_conv2d_fprop_with_broadcast.h +/// to invoke CustomImplicitGemmConvolutionWithFusedEpilogue +template , + int AlignmentB = 128 / cutlass::sizeof_bits_v> +struct CustomDefaultConv2dFpropWithBroadcast { + using Base = cutlass::conv::kernel::DefaultConv2dFpropWithBroadcast< + ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC, ElementAccumulator, OperatorClass, + ArchTag, ThreadblockShape, WarpShape, InstructionShape, EpilogueOutputOp, ThreadblockSwizzle, + Stages, MathOperatorTag, IteratorAlgorithm, StrideSupport, AlignmentA, AlignmentB>; + using Kernel = + CustomImplicitGemmConvolutionWithFusedEpilogue; +}; + +/// Original file: cutlass/conv/kernel/implicit_gemm_convolution_strided_dgrad.h +/// to add PDL sync points +template +struct CustomImplicitGemmConvolutionStridedDgrad { + using Base = + cutlass::conv::kernel::ImplicitGemmConvolutionStridedDgrad; + using ElementA = typename Base::ElementA; + using LayoutA = typename Base::LayoutA; + using ElementB = typename Base::ElementB; + using LayoutB = typename Base::LayoutB; + using ElementC = typename Base::ElementC; + using LayoutC = typename Base::LayoutC; + using ElementAccumulator = typename Base::ElementAccumulator; + using ElementCompute = typename Base::ElementCompute; + using OperatorClass = typename Base::OperatorClass; + using ArchTag = typename Base::ArchTag; + using ThreadblockShape = typename Base::ThreadblockShape; + using WarpShape = typename Base::WarpShape; + using InstructionShape = typename Base::InstructionShape; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + using EpilogueOutputOp = typename Base::EpilogueOutputOp; + static int const kStages = Base::kStages; + static int const kConvDim = Base::kConvDim; + using WarpMmaOperator = typename Base::WarpMmaOperator; + using ArchMmaOperator = typename Base::ArchMmaOperator; + using MathOperator = typename Base::MathOperator; + + static cutlass::conv::Operator const kConvolutionalOperator = Base::kConvolutionalOperator; + static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Base::kIteratorAlgorithm; + static cutlass::conv::StrideSupport const kStrideSupport = Base::kStrideSupport; + static cutlass::conv::GroupMode const kGroupMode = Base::kGroupMode; + + using Arguments = typename Base::Arguments; + using Mma = typename Base::Mma; + using Epilogue = typename Base::Epilogue; + using Params = typename Base::Params; + using SharedStorage = typename Base::SharedStorage; + + using ConvOutputIteratorParameter = typename Base::ConvOutputIteratorParameter; + + /// Executes one ImplicitGEMM + CUTLASS_DEVICE + void operator()(Params const& params, SharedStorage& shared_storage) + { + // Compute threadblock location + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord threadblock_tile_idx = + threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // Early exit if CTA is out of range + if (params.grid_tiled_shape.m() <= threadblock_tile_idx.m() + || params.grid_tiled_shape.n() <= threadblock_tile_idx.n()) { + cudaGDC(); + return; + } + + // Compute position within threadblock + int thread_idx = threadIdx.x; + + // Compute starting filter position for strided dgrad + int tile_m_per_filter = + strided_dgrad_tile_m_per_filter(params.problem_size, ThreadblockShape::kM); + int filter_tile_m = (threadblock_tile_idx.m() / tile_m_per_filter); + + int start_r; + int start_s; + params.stride_w_divmod(start_r, start_s, filter_tile_m); + + int filter_r = start_r; + int filter_s = start_s; + + // Starting h, w positions for filter position in gemm_k=0 + int start_h; + int start_w; + strided_dgrad_starting_coords(params.problem_size, params.stride_h_divmod, + params.stride_w_divmod, filter_r, filter_s, start_h, start_w); + + if (start_h >= params.problem_size.H || start_w >= params.problem_size.W) { + cudaGDC(); + return; + } + + typename Mma::FragmentC accumulators; + + accumulators.clear(); + + // Broadcast the warp_id computed by lane 0 to ensure dependent code + // is compiled as warp-uniform. + int warp_idx = cutlass::canonical_warp_idx_sync(); + int lane_idx = threadIdx.x % 32; + + // Check if CTA contributes valid MMA (Dy * w) and accumulator will be non-zero after MMA + if (start_r < params.problem_size.R && start_s < params.problem_size.S) { + // Scale gemm_k_iterations for strided dgrad + int gemm_k_iterations = + (params.gemm_k_iterations / (params.problem_size.R * params.problem_size.S)) + * params.problem_size.num_gemm_k_filter_positions(start_r, start_s); + + // Construct iterators to A and B operands + typename Mma::IteratorA iterator_A( + params.iterator_A, params.problem_size, params.ptr_A, thread_idx, + params.stride_h_divmod, params.stride_w_divmod, start_r, start_s, + cutlass::MatrixCoord(threadblock_tile_idx.m() * Mma::Shape::kM, + threadblock_tile_idx.k() * Mma::Shape::kK)); + + typename Mma::IteratorB iterator_B( + params.iterator_B, params.problem_size, params.ptr_B, thread_idx, start_r, start_s, + cutlass::MatrixCoord(threadblock_tile_idx.k() * Mma::Shape::kK, + threadblock_tile_idx.n() * Mma::Shape::kN)); + + // + // Main loop + // + + // Construct thread-scoped matrix multiply + Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx); + + // Compute threadblock-scoped matrix multiply-add + cudaGDC(); + mma(gemm_k_iterations, accumulators, iterator_A, iterator_B, accumulators); + } else { + cudaGDC(); + } + + // + // Epilogue + // + + EpilogueOutputOp output_op(params.output_op); + + // Construct the semaphore. + int block_idx = + threadblock_tile_idx.m() + threadblock_tile_idx.n() * params.grid_tiled_shape.m(); + cutlass::Semaphore semaphore(params.semaphore + block_idx, thread_idx); + + // Compute logical position within grid + threadblock_tile_idx = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile); + + // If performing a reduction via split-K, fetch the initial synchronization + if (params.split_k_mode == cutlass::conv::SplitKMode::kSerial + && params.grid_tiled_shape.k() > 1) { + + // Fetch the synchronization lock initially but do not block. + semaphore.fetch(); + + // Indicate which position in a serial reduction the output operator is currently updating + output_op.set_k_partition(threadblock_tile_idx.k(), params.grid_tiled_shape.k()); + } + + cutlass::MatrixCoord threadblock_offset(threadblock_tile_idx.m() * Mma::Shape::kM, + threadblock_tile_idx.n() * Mma::Shape::kN); + + // Tile iterator writing to destination tensor + typename Epilogue::OutputTileIterator iterator_D( + params.iterator_D, params.ptr_D, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, + params.stride_h_divmod, params.stride_w_divmod, start_r, start_s, threadblock_offset); + + // Construct the epilogue + Epilogue epilogue(shared_storage.epilogue, thread_idx, warp_idx, lane_idx); + + if (output_op.is_source_needed()) { + // Tile iterator reading from source accumulator tensor + typename Epilogue::OutputTileIterator iterator_C( + params.iterator_C, params.ptr_C, + ConvOutputIteratorParameter::extent(params.problem_size), thread_idx, + params.stride_h_divmod, params.stride_w_divmod, start_r, start_s, threadblock_offset); + + // Wait on the semaphore - this latency may have been covered by iterator construction + if (params.split_k_mode == cutlass::conv::SplitKMode::kSerial + && params.grid_tiled_shape.k() > 1) { + + // For subsequent threadblocks, the source matrix is held in the 'D' tensor. + if (threadblock_tile_idx.k()) { + iterator_C = iterator_D; + } + + semaphore.wait(threadblock_tile_idx.k()); + } + + // Run epilogue with addend source iterator + epilogue(output_op, iterator_D, accumulators, iterator_C); + } else { + // Run epilogue without addend source iterator + epilogue(output_op, iterator_D, accumulators); + } + + // + // Release the semaphore + // + + if (params.split_k_mode == cutlass::conv::SplitKMode::kSerial + && params.grid_tiled_shape.k() > 1) { + + int lock = 0; + if (params.grid_tiled_shape.k() == threadblock_tile_idx.k() + 1) { + // The final threadblock resets the semaphore for subsequent grids. + lock = 0; + } else { + // Otherwise, the semaphore is incremented + lock = threadblock_tile_idx.k() + 1; + } + + semaphore.release(lock); + } + } +}; + +/// Original file: cutlass/conv/kernel/default_conv2d_dgrad.h +/// to invoke CustomImplicitGemmConvolutionStridedDgrad +template ::value, + int AlignmentB = 128 / cutlass::sizeof_bits::value> +struct CustomDefaultConv2dDgrad { + using Base = cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC, ElementAccumulator, OperatorClass, + ArchTag, ThreadblockShape, WarpShape, InstructionShape, EpilogueOutputOp, ThreadblockSwizzle, + Stages, MathOperatorTag, IteratorAlgorithm, StrideSupport, AlignmentA, AlignmentB>; + using Kernel = + CustomImplicitGemmConvolutionStridedDgrad; +}; + +/// Original file: cutlass/conv/device/implicit_gemm_convolution.h +/// to add "cudaLaunchKernelEx" to run() +template +class CustomImplicitGemmConvolution { +public: + using Base = cutlass::conv::device::ImplicitGemmConvolution; + using UnderlyingKernel = typename Base::UnderlyingKernel; + using Arguments = typename Base::Arguments; + using ThreadblockSwizzle = typename Base::ThreadblockSwizzle; + + static int const kWarpCount = Base::kWarpCount; + +private: + typename UnderlyingKernel::Params params_; + +public: + cutlass::Status run(cudaStream_t stream = nullptr) + { + ThreadblockSwizzle threadblock_swizzle; + + dim3 grid = threadblock_swizzle.get_grid_shape(params_.grid_tiled_shape); + dim3 block(32 * kWarpCount, 1, 1); + + int smem_size = int(sizeof(typename UnderlyingKernel::SharedStorage)); + cutlass::Status launch_result = cutlass::Status::kSuccess; + + cutlass::arch::synclog_setup(); + + cudaLaunchConfig_t config; + config.gridDim = grid; + config.blockDim = block; + config.dynamicSmemBytes = smem_size; + config.stream = stream; + auto attr = get_cuda_launch_attribute(); + config.attrs = &attr; + config.numAttrs = 1; + + cudaLaunchKernelEx(&config, &cutlass::Kernel, params_); + + cudaError_t result = cudaGetLastError(); + if (cudaSuccess == result && cutlass::Status::kSuccess == launch_result) { + return cutlass::Status::kSuccess; + } else { + CUTLASS_TRACE_HOST(" Kernel launch failed. Reason: " << result); + return cutlass::Status::kErrorInternal; + } + } + + cutlass::Status initialize(Arguments const& args, void* workspace = nullptr, + cudaStream_t stream = nullptr) + { + // initialize the params structure from the arguments + params_ = typename UnderlyingKernel::Params(args, static_cast(workspace)); + + int smem_size = int(sizeof(typename UnderlyingKernel::SharedStorage)); + + if (smem_size >= (48 << 10)) { + cudaError_t result = + cudaFuncSetAttribute(cutlass::Kernel, + cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size); + + if (result != cudaSuccess) { + return cutlass::Status::kErrorInternal; + } + } + + return cutlass::Status::kSuccess; + } + + cutlass::Status operator()(Arguments const& args, void* workspace = nullptr, + cudaStream_t stream = nullptr) + { + + cutlass::Status status = initialize(args, workspace, stream); + + if (status == cutlass::Status::kSuccess) { + status = run(stream); + } + + return status; + } + + static cutlass::Status can_implement(Arguments const& args) + { + return Base::can_implement(args); + } +}; diff --git a/src/layers/extensions/inference/def_const.h b/src/layers/extensions/inference/def_const.h new file mode 100644 index 0000000..0557cb9 --- /dev/null +++ b/src/layers/extensions/inference/def_const.h @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +constexpr float SCALE_MIN = 0.11f; +constexpr float SCALE_MAX = 16.f; +constexpr float LOG_SCALE_MIN = -2.2073f; // std::log(SCALE_MIN); +constexpr float LOG_SCALE_MAX = 2.7726f; // std::log(SCALE_MAX) +constexpr int SCALE_LEVEL = 128; +constexpr float LOG_SCALE_STEP = (LOG_SCALE_MAX - LOG_SCALE_MIN) / (SCALE_LEVEL - 1); +constexpr float LOG_SCALE_STEP_RECIP = 1.f / LOG_SCALE_STEP; + +constexpr int COND_KERNEL_THREAD_NUM1 = 1024; +constexpr int COND_KERNEL_THREAD_NUM2 = 1024; +constexpr int COND_KERNEL_PER_THREAD_NUM = 8; + +constexpr int MIN_SYMBOLS_PER_STREAM = 32768; diff --git a/src/layers/extensions/inference/def_cutlass.h b/src/layers/extensions/inference/def_cutlass.h new file mode 100644 index 0000000..7bface5 --- /dev/null +++ b/src/layers/extensions/inference/def_cutlass.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "def_const.h" + +at::Tensor conv1x1_bias(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, at::Tensor& out_buf); +at::Tensor conv1x1_bias_shortcut(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const at::Tensor& shortcut, + at::Tensor& out_buf); +at::Tensor conv1x1_bias_shortcut2(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const at::Tensor& shortcut1, + const at::Tensor& shortcut2, at::Tensor& out_buf); +at::Tensor conv1x1_bias_shortcut_with_quant(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& bias, + const at::Tensor& shortcut, const at::Tensor& quant, + at::Tensor& out_buf); +at::Tensor conv1x1_bias_with_quant(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& bias, + const at::Tensor& quant, at::Tensor& out_buf); +at::Tensor conv1x1_bias_wsilu(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, at::Tensor& out_buf); +at::Tensor conv1x1_bias_wsilu_chunk_add(const int sm, const at::Tensor& feature, + const at::Tensor& weight, const at::Tensor& bias, + const at::Tensor& weight0, const at::Tensor& weight1, + const at::Tensor& weight2, const at::Tensor& weight3, + const at::Tensor& bias0, const at::Tensor& bias1, + const at::Tensor& bias2, const at::Tensor& bias3, + at::Tensor& out_buf); +at::Tensor conv2d(const at::Tensor& feature, const at::Tensor& weight, const at::Tensor& bias, + const int stride, at::Tensor& out_buf); +at::Tensor conv_bias(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const at::Tensor& bias, const int stride, at::Tensor& out_buf); +at::Tensor d3x3(const int sm, const at::Tensor& feature, const at::Tensor& weight, at::Tensor& out_buf); +at::Tensor transposed_conv(const int sm, const at::Tensor& feature, const at::Tensor& weight, + const int stride, at::Tensor& out_buf); diff --git a/src/layers/extensions/inference/def_elementwise.h b/src/layers/extensions/inference/def_elementwise.h new file mode 100644 index 0000000..64a2b19 --- /dev/null +++ b/src/layers/extensions/inference/def_elementwise.h @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "def_const.h" + +at::Tensor add_and_multiply_broadcast_cuda(const at::Tensor& x0, const at::Tensor& x1, + const at::Tensor& q, at::Tensor& out_buf); +at::Tensor add_and_multiply_with_clamp_min_inplace_cuda(at::Tensor& x0, const at::Tensor& x1, + const at::Tensor& q); +std::tuple +build_index_dec_cuda(const at::Tensor& scales, const float skip_thres_float, + const at::optional& fx, const int32_t skip_thres_int, + at::Tensor& out_buf, at::Tensor& cond_out_buf); +std::tuple +build_index_enc_cuda(const at::Tensor& symbols, const at::Tensor& scales, + const float skip_thres_float, const at::optional& fx, + const int32_t skip_thres_int, at::Tensor& out_buf, at::Tensor& cond_out_buf); +std::tuple +conditional_index_part1_cuda(const at::Tensor& x, const at::Tensor& m, at::Tensor& out_buf, + at::Tensor& total_num_buf, at::Tensor& num_buf); +at::Tensor conditional_index_part2_cuda(const at::Tensor& x, const at::Tensor& s, + int* size_ptr = nullptr); +at::Tensor conditional_recover_with_type_conversion_cuda(const at::Tensor& x, const at::Tensor& m, + const at::Tensor& num, + const at::ScalarType dtype, + at::Tensor& out_buf); +at::Tensor divide_with_clamp_min_inplace_cuda(at::Tensor& y, const at::Tensor& q); +at::Tensor int8_to_dtype_cuda(const at::Tensor& x, const at::ScalarType dtype, const int C, + const int H, const int W, at::Tensor& out_buf); +at::Tensor multiply_with_broadcast_cuda(const at::Tensor& a, const at::Tensor& b, at::Tensor& out_buf); +at::Tensor pad_and_unshuffle_8_cuda(const at::Tensor& x, const int padB, const int padR, + at::Tensor& out_buf); +at::Tensor pixel_shuffle_2_cuda(const at::Tensor& x, at::Tensor& out_buf); +at::Tensor pixel_shuffle_8_cuda(const at::Tensor& x, bool clamp, at::Tensor& out_buf); +at::Tensor pixel_unshuffle_cuda(const at::Tensor& x, const int downscale_factor, at::Tensor& out_buf); +std::tuple +process_with_mask_cuda(const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, + const at::Tensor& mask, const float force_zero_thres_float, + const int32_t force_zero_thres_int, at::Tensor& y_q_buf, + at::Tensor& y_hat_buf, at::Tensor& s_hat_buf); +std::tuple process_with_mask_no_scale_add_and_multiply_inplace_cuda( + const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& y_q, at::Tensor& y_hat, const at::Tensor& quant, const float force_zero_thres_float, + const int32_t force_zero_thres_int); +std::tuple process_with_mask_no_scale_add_inplace_cuda( + const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& y_q, at::Tensor& y_hat, const float force_zero_thres_float, + const int32_t force_zero_thres_int); +std::tuple process_with_mask_no_scale_cuda( + const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, const at::Tensor& mask, + const float force_zero_thres_float, const int32_t force_zero_thres_int, at::Tensor& y_q_buf, + at::Tensor& y_hat_buf); +at::Tensor replicate_pad_cuda(const at::Tensor& x, const int padB, const int padR, at::Tensor& out_buf); +at::Tensor restore_y_4x_add_and_multiply_broadcast_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, + const at::Tensor& y_hat_so_far, + const at::Tensor& q, at::Tensor& out_buf); +at::Tensor restore_y_4x_and_add_inplace_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, at::Tensor& y_hat); +at::Tensor restore_y_4x_cuda(const at::Tensor& y, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& out_buf); +at::Tensor restore_y_and_add_inplace_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, at::Tensor& y_hat); +at::Tensor restore_y_and_add_multiply_inplace_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, at::Tensor& y_hat, + const at::Tensor& q); +at::Tensor restore_y_cuda(const at::Tensor& y, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& out_buf); +std::tuple round_z_cuda(const at::Tensor& z, at::Tensor& z_hat_buf, + at::Tensor& z_int8_buf); +at::Tensor single_part_for_reading_4x_cuda(const at::Tensor& x, const at::Tensor& mask, + at::Tensor& out_buf); +at::Tensor single_part_for_writing_4x_cuda(const at::Tensor& x, at::Tensor& out_buf); +at::Tensor slice_cuda(const at::Tensor& x, const int H, const int W, at::Tensor& out_buf); diff --git a/src/layers/extensions/inference/dmc_common.cpp b/src/layers/extensions/inference/dmc_common.cpp new file mode 100644 index 0000000..0610d24 --- /dev/null +++ b/src/layers/extensions/inference/dmc_common.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "dmc_common.h" + +#include + +#include "def_elementwise.h" + +void DMCCommon::capture_cuda_graph(cudaGraphExec_t& gexec, const cudaStream_t& stream, + const std::function& lambda) +{ + cudaGraph_t graph; + destroy_cuda_graph_exec(gexec); + CUDA_CHECK(cudaStreamBeginCapture(stream, cudaStreamCaptureModeThreadLocal)); + try { + lambda(); + } catch (...) { + // End capture to restore the stream from capture mode, then discard the graph. + cudaStreamEndCapture(stream, &graph); + if (graph != nullptr) { + cudaGraphDestroy(graph); + } + throw; + } + CUDA_CHECK(cudaStreamEndCapture(stream, &graph)); + CUDA_CHECK(cudaGraphInstantiate(&gexec, graph, nullptr, nullptr, 0)); + cudaGraphDestroy(graph); +} + +int DMCCommon::compute_ec_parallel(int symbol_count) +{ + int n = symbol_count / MIN_SYMBOLS_PER_STREAM; + return std::max(1, std::min(MAX_EC_PARALLEL, n)); +} + +at::Tensor DMCCommon::crop_hyper_params(const at::Tensor& hyper_params, const int H, const int W, + at::Tensor& hyper_params_out) +{ + const int H0 = hyper_params.size(2); + const int W0 = hyper_params.size(3); + if (H0 == H && W0 == W) { + return hyper_params; + } + hyper_params_out = slice_cuda(hyper_params, H, W, hyper_params_out); + return hyper_params_out; +} + +void DMCCommon::destroy_cuda_graph_exec(cudaGraphExec_t& gexec) +{ + if (gexec != nullptr) { + cudaGraphExecDestroy(gexec); + gexec = nullptr; + } +} + +at::Tensor DMCCommon::get_one_mask(const at::Tensor& micro_mask, int H, int W) +{ + auto mask = micro_mask.repeat({ (H + 1) / 2, (W + 1) / 2 }); + mask = mask.slice(0, 0, H).slice(1, 0, W); + return mask.unsqueeze(0).unsqueeze(0); +} + +std::tuple DMCCommon::get_padding_size(const int height, const int width, const int p) +{ + const int new_h = (height + p - 1) / p * p; + const int new_w = (width + p - 1) / p * p; + const int padding_right = new_w - width; + const int padding_bottom = new_h - height; + return { padding_right, padding_bottom }; +} + +at::Tensor DMCCommon::pad_for_y(const at::Tensor& y, at::Tensor& y_pad) +{ + const int H = y.size(2); + const int W = y.size(3); + auto [padding_right, padding_bottom] = get_padding_size(H, W, 4); + if (padding_right == 0 && padding_bottom == 0) { + return y; + } + y_pad = replicate_pad_cuda(y, padding_bottom, padding_right, y_pad); + return y_pad; +} + +void DMCCommon::run(const std::function& lambda, cudaGraphExec_t& gexec) +{ + auto stream = at::cuda::getCurrentCUDAStream(); + if (gexec == nullptr) { + capture_cuda_graph(gexec, stream, lambda); + } + + CUDA_CHECK(cudaGraphLaunch(gexec, stream)); +} + +void DMCCommon::run(const std::function& lambda, cudaGraphExec_t (&gexec)[g_qp_num], + const int qp) +{ + auto stream = at::cuda::getCurrentCUDAStream(); + if (gexec[0] == nullptr) { + for (int i = 0; i < g_qp_num; ++i) { + capture_cuda_graph(gexec[i], stream, [&]() { lambda(i); }); + } + } + + CUDA_CHECK(cudaGraphLaunch(gexec[qp], stream)); +} + +void DMCCommon::run(const std::function& lambda, cudaGraphExec_t (&gexec)[2], + const bool bvalue) +{ + auto stream = at::cuda::getCurrentCUDAStream(); + if (gexec[0] == nullptr) { + for (int i = 0; i < 2; ++i) { + capture_cuda_graph(gexec[i], stream, [&]() { lambda(static_cast(i)); }); + } + } + + CUDA_CHECK(cudaGraphLaunch(gexec[bvalue ? 1 : 0], stream)); +} + +void DMCCommon::run(const std::function& lambda, + cudaGraphExec_t (&gexec)[g_qp_num][2], const int qp, const bool bvalue) +{ + auto stream = at::cuda::getCurrentCUDAStream(); + if (gexec[0][0] == nullptr) { + for (int i = 0; i < g_qp_num; ++i) { + for (int j = 0; j < 2; ++j) { + capture_cuda_graph(gexec[i][j], stream, [&]() { lambda(i, static_cast(j)); }); + } + } + } + + CUDA_CHECK(cudaGraphLaunch(gexec[qp][bvalue ? 1 : 0], stream)); +} diff --git a/src/layers/extensions/inference/dmc_common.h b/src/layers/extensions/inference/dmc_common.h new file mode 100644 index 0000000..56590e2 --- /dev/null +++ b/src/layers/extensions/inference/dmc_common.h @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +#include "cuda_check.h" +#include "def_const.h" +#include "layers_proxy.h" +#include "py_rans.h" + +enum class DMCWorkType { + Encode, + DecodeZ, + DecodeY, +}; + +class DMCCommon { +public: + static constexpr int g_qp_num = 64; + +public: + DMCCommon() = default; + ~DMCCommon() = default; + +public: + static void capture_cuda_graph(cudaGraphExec_t& gexec, const cudaStream_t& stream, + const std::function& lambda); + static int compute_ec_parallel(int symbol_count); + static void destroy_cuda_graph_exec(cudaGraphExec_t& gexec); + static at::Tensor get_one_mask(const at::Tensor& micro_mask, int H, int W); + static std::tuple get_padding_size(const int height, const int width, const int p); + static void run(const std::function& lambda, cudaGraphExec_t& gexec); + static void run(const std::function& lambda, cudaGraphExec_t (&gexec)[g_qp_num], + const int qp); + static void run(const std::function& lambda, cudaGraphExec_t (&gexec)[2], + const bool bvalue); + static void run(const std::function& lambda, + cudaGraphExec_t (&gexec)[g_qp_num][2], const int qp, const bool bvalue); + + template + static std::shared_ptr> tensor_to_vector_1d(const at::Tensor& x) + { + auto vec = std::make_shared>(x.numel()); + if constexpr (is_gpu) { + CUDA_CHECK(cudaMemcpyAsync(vec->data(), x.data_ptr(), x.numel() * sizeof(T), + cudaMemcpyDeviceToHost, at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaStreamSynchronize(at::cuda::getCurrentCUDAStream())); + } else { + memcpy(vec->data(), x.data_ptr(), x.numel() * sizeof(T)); + } + return vec; + } + +protected: + at::Tensor crop_hyper_params(const at::Tensor& hyper_params, const int H, const int W, + at::Tensor& hyper_params_out); + at::Tensor pad_for_y(const at::Tensor& y, at::Tensor& y_pad); + +protected: + int m_entropy_coder_parallel{ 0 }; + RansEncoder m_entropy_encoder; + RansDecoder m_entropy_decoder; +}; diff --git a/src/layers/extensions/inference/dmc_htl_proxy.cpp b/src/layers/extensions/inference/dmc_htl_proxy.cpp new file mode 100644 index 0000000..7b523a4 --- /dev/null +++ b/src/layers/extensions/inference/dmc_htl_proxy.cpp @@ -0,0 +1,1178 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include + +#include "common_cpp.h" +#include "cuda_check.h" +#include "def_cutlass.h" +#include "def_elementwise.h" +#include "dmc_htl_proxy.h" +#include "memory_pool.h" + +at::Tensor DMCHTLDecoderProxy::forward(const at::Tensor& x, const at::Tensor& conv1_input, + const at::Tensor& quant) +{ + auto out = forward_part1(x); + out = forward_part2(conv1_input, quant); + return out; +} + +at::Tensor DMCHTLDecoderProxy::forward_part1(const at::Tensor& x) +{ + return m_up.forward(x); +} + +at::Tensor DMCHTLDecoderProxy::forward_part2(const at::Tensor& x, const at::Tensor& quant) +{ + auto out = m_conv10.forward(x); + out = m_conv11.forward(out); + out = m_conv12.forward(out); + out = m_conv13.forward(out); + out = m_conv14.forward(out); + out = m_conv15.forward(out); + out = m_conv16.forward(out); + out = m_conv17.forward(out); + out = m_conv18.forward(out); + out = m_conv19.forward(out); + out = m_conv1a.forward(out); + out = multiply_with_broadcast_cuda(out, quant, out); + return out; +} + +at::Tensor DMCHTLDecoderProxy::pre_allocate_tensors(at::Tensor& x, at::Tensor& up_out_buf, + at::Tensor& conv1_input_buf, + const at::Tensor& out_buf) +{ + m_up.pre_allocate_tensors(x, up_out_buf); + m_conv1_out = out_buf; + auto out = m_conv10.pre_allocate_tensors(conv1_input_buf, true); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv12.pre_allocate_tensors(out); + out = m_conv13.pre_allocate_tensors(out); + out = m_conv14.pre_allocate_tensors(out); + out = m_conv15.pre_allocate_tensors(out); + out = m_conv16.pre_allocate_tensors(out); + out = m_conv17.pre_allocate_tensors(out); + out = m_conv18.pre_allocate_tensors(out); + out = m_conv19.pre_allocate_tensors(out); + out = m_conv1a.pre_allocate_tensors(out, false, m_conv1_out); + + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv12.release_tensors(); + m_conv13.release_tensors(); + m_conv14.release_tensors(); + m_conv15.release_tensors(); + m_conv16.release_tensors(); + m_conv17.release_tensors(); + m_conv18.release_tensors(); + m_conv19.release_tensors(); + m_conv1a.release_tensors(); + g_tensor_pool.set_reusable(m_conv1_out, false); + return m_conv1_out; +} + +void DMCHTLDecoderProxy::set_param(const std::map& state_dict) +{ + m_up.set_param(get_submodule_state_dict(state_dict, "up.")); + m_conv10.set_param(get_submodule_state_dict(state_dict, "conv1.0.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "conv1.1.")); + m_conv12.set_param(get_submodule_state_dict(state_dict, "conv1.2.")); + m_conv13.set_param(get_submodule_state_dict(state_dict, "conv1.3.")); + m_conv14.set_param(get_submodule_state_dict(state_dict, "conv1.4.")); + m_conv15.set_param(get_submodule_state_dict(state_dict, "conv1.5.")); + m_conv16.set_param(get_submodule_state_dict(state_dict, "conv1.6.")); + m_conv17.set_param(get_submodule_state_dict(state_dict, "conv1.7.")); + m_conv18.set_param(get_submodule_state_dict(state_dict, "conv1.8.")); + m_conv19.set_param(get_submodule_state_dict(state_dict, "conv1.9.")); + m_conv1a.set_param(get_submodule_state_dict(state_dict, "conv1.10.")); +} + +at::Tensor DMCHTLEncoderProxy::forward(const at::Tensor& x, const at::Tensor& quant) +{ + const int sm = get_gpu_sm(); + auto out = m_conv10.forward(x); + out = m_conv11.forward(out); + out = m_conv12.forward(out); + out = m_conv13.forward(out); + out = m_conv14.forward(out); + out = m_conv15.forward(out); + out = m_conv16.forward(out); + out = multiply_with_broadcast_cuda(out, quant, out); + out = conv_bias(sm, out, m_down_weight, m_down_bias, 2, m_down_out); + return out; +} + +at::Tensor DMCHTLEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_down_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_down = m_down_weight.size(0); + m_down_out = g_tensor_pool.empty({ 1, ch_down, H / 2, W / 2 }, options); + auto out = m_conv10.pre_allocate_tensors(x, true); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv12.pre_allocate_tensors(out); + out = m_conv13.pre_allocate_tensors(out); + out = m_conv14.pre_allocate_tensors(out); + out = m_conv15.pre_allocate_tensors(out); + out = m_conv16.pre_allocate_tensors(out); + + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv12.release_tensors(); + m_conv13.release_tensors(); + m_conv14.release_tensors(); + m_conv15.release_tensors(); + m_conv16.release_tensors(); + return m_down_out; +} + +void DMCHTLEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv10.set_param(get_submodule_state_dict(state_dict, "conv1.0.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "conv1.1.")); + m_conv12.set_param(get_submodule_state_dict(state_dict, "conv1.2.")); + m_conv13.set_param(get_submodule_state_dict(state_dict, "conv1.3.")); + m_conv14.set_param(get_submodule_state_dict(state_dict, "conv1.4.")); + m_conv15.set_param(get_submodule_state_dict(state_dict, "conv1.5.")); + m_conv16.set_param(get_submodule_state_dict(state_dict, "conv1.6.")); + m_down_weight = state_dict.at("down.weight"); + m_down_bias = state_dict.at("down.bias"); +} + +at::Tensor DMCHTLFeatureAdaptorIProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCHTLFeatureAdaptorIProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTLFeatureAdaptorIProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); +} + +at::Tensor DMCHTLFeatureAdaptorMProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + out = m_conv4.forward(out); + out = m_conv5.forward(out); + out = m_conv6.forward(out); + out = m_conv7.forward(out); + out = m_conv8.forward(out); + out = m_conv9.forward(out); + return out; +} + +at::Tensor DMCHTLFeatureAdaptorMProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out); + out = m_conv4.pre_allocate_tensors(out); + out = m_conv5.pre_allocate_tensors(out); + out = m_conv6.pre_allocate_tensors(out); + out = m_conv7.pre_allocate_tensors(out); + out = m_conv8.pre_allocate_tensors(out); + out = m_conv9.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + m_conv4.release_tensors(); + m_conv5.release_tensors(); + m_conv6.release_tensors(); + m_conv7.release_tensors(); + m_conv8.release_tensors(); + m_conv9.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTLFeatureAdaptorMProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); + m_conv4.set_param(get_submodule_state_dict(state_dict, "conv.4.")); + m_conv5.set_param(get_submodule_state_dict(state_dict, "conv.5.")); + m_conv6.set_param(get_submodule_state_dict(state_dict, "conv.6.")); + m_conv7.set_param(get_submodule_state_dict(state_dict, "conv.7.")); + m_conv8.set_param(get_submodule_state_dict(state_dict, "conv.8.")); + m_conv9.set_param(get_submodule_state_dict(state_dict, "conv.9.")); +} + +at::Tensor DMCHTLFeatureExtractorProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + return out; +} + +at::Tensor DMCHTLFeatureExtractorProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTLFeatureExtractorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); +} + +at::Tensor DMCHTLHyperDecoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCHTLHyperDecoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTLHyperDecoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0."), true); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), true); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); +} + +at::Tensor DMCHTLHyperEncoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCHTLHyperEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTLHyperEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), true); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2."), true); +} + +at::Tensor DMCHTLPriorFusionProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCHTLPriorFusionProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_conv3_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_conv3 = m_conv3_weight.size(0); + m_conv3_out = g_tensor_pool.empty({ 1, ch_conv3, H, W }, options); + // x is a cat parameter, will be further used + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCHTLPriorFusionProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +at::Tensor DMCHTLReconHeadProxy::forward_reset(const at::Tensor& x) +{ + constexpr int conv_index = g_frame_delay - 1; + const int sm = get_gpu_sm(); + auto out = m_conv0[conv_index].forward(x); + out = m_conv1[conv_index].forward(out); + out = m_conv2[conv_index].forward(out); + out = m_conv3[conv_index].forward(out); + out = m_conv4[conv_index].forward(out); + out = conv1x1_bias(sm, out, m_head_weight[conv_index], m_head_bias[conv_index], + m_head_out[conv_index]); + return out; +} + +std::tuple, at::Tensor> DMCHTLReconHeadProxy::forward(const at::Tensor& x) +{ + at::Tensor for_reset; + const int sm = get_gpu_sm(); + auto all_out = std::vector(g_frame_delay); + for (int i = 0; i < g_frame_delay; i++) { + auto out = m_conv0[i].forward(x); + out = m_conv1[i].forward(out); + out = m_conv2[i].forward(out); + out = m_conv3[i].forward(out); + out = m_conv4[i].forward(out); + out = conv1x1_bias(sm, out, m_head_weight[i], m_head_bias[i], m_head_out[i]); + if (i == g_frame_delay - 1) { + for_reset = out; + } + out = pixel_shuffle_8_cuda(out, true, m_shuffle_out[i]); + all_out[i] = out; + } + return { all_out, for_reset }; +} + +at::Tensor DMCHTLReconHeadProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_head_weight[0].options().memory_format(at::MemoryFormat::ChannelsLast); + const int C = m_head_weight[0].size(0); + for (int i = 0; i < g_frame_delay; i++) { + if (i != g_frame_delay - 1) { + m_head_out[i] = g_tensor_pool.empty({ 1, C, H, W }, options); + } else { + m_head_out[i] = out_buf; + } + m_shuffle_out[i] = at::empty({ 1, C / 64, H * 8, W * 8 }, options); + + auto out = m_conv0[i].pre_allocate_tensors(x, true); // must not modify! + out = m_conv1[i].pre_allocate_tensors(out); + out = m_conv2[i].pre_allocate_tensors(out); + out = m_conv3[i].pre_allocate_tensors(out); + out = m_conv4[i].pre_allocate_tensors(out); + if (i != g_frame_delay - 1) { + g_tensor_pool.release(m_head_out[i]); + } + m_conv0[i].release_tensors(); + m_conv1[i].release_tensors(); + m_conv2[i].release_tensors(); + m_conv3[i].release_tensors(); + m_conv4[i].release_tensors(); + } + return m_head_out[g_frame_delay - 1]; +} + +void DMCHTLReconHeadProxy::set_param(const std::map& state_dict) +{ + for (int i = 0; i < g_frame_delay; i++) { + m_conv0[i].set_param(get_submodule_state_dict(state_dict, "conv." + std::to_string(i) + ".0.")); + m_conv1[i].set_param(get_submodule_state_dict(state_dict, "conv." + std::to_string(i) + ".1.")); + m_conv2[i].set_param(get_submodule_state_dict(state_dict, "conv." + std::to_string(i) + ".2.")); + m_conv3[i].set_param(get_submodule_state_dict(state_dict, "conv." + std::to_string(i) + ".3.")); + m_conv4[i].set_param(get_submodule_state_dict(state_dict, "conv." + std::to_string(i) + ".4.")); + m_head_weight[i] = state_dict.at("conv." + std::to_string(i) + ".5.weight"); + m_head_bias[i] = state_dict.at("conv." + std::to_string(i) + ".5.bias"); + } +} + +at::Tensor DMCHTLSpatialPriorProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCHTLSpatialPriorProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + m_conv3_out = out_buf; + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCHTLSpatialPriorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +at::Tensor DMCHTLTemporalPriorEncoderProxy::forward(const at::Tensor& x) +{ + return m_conv.forward(x); +} + +at::Tensor DMCHTLTemporalPriorEncoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv.pre_allocate_tensors(x, out_buf); + m_conv.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTLTemporalPriorEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv.set_param(get_submodule_state_dict(state_dict, "conv."), true); +} + +DMCHTLProxy::DMCHTLProxy() +{ + CUDA_CHECK(cudaMallocHost((void**)&m_size_ptr, sizeof(int))); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y_ready, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_z_ready, cudaEventDisableTiming)); + m_thread = std::thread(&DMCHTLProxy::worker, this); +} + +DMCHTLProxy::~DMCHTLProxy() +{ + { + std::lock_guard lk(m_mutex_pending); + m_finish = true; + } + m_cv_pending.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } + cudaEventDestroy(m_event_y); + cudaEventDestroy(m_event_y_ready); + cudaEventDestroy(m_event_z_ready); + cudaFreeHost(m_size_ptr); + + clear_cuda_graph(); +} + +void DMCHTLProxy::worker() +{ + at::cuda::CUDAStream high_priority_stream = at::cuda::getStreamFromPool(true); + at::cuda::CUDAStreamGuard guard(high_priority_stream); + + while (!m_finish) { + std::unique_lock lk(m_mutex_pending); + m_cv_pending.wait(lk, [this] { return m_pending || m_finish; }); + if (m_finish) { + break; + } + m_pending = false; + lk.unlock(); + + if (m_pending_work == DMCWorkType::Encode) { + m_entropy_encoder.reset(); + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + + // build_index_enc and conditional_index for each of the 4 mask steps + // Process in reverse order (3,2,1,0) to match Python encode order + int total_symbol_count = 0; + for (int i = 3; i >= 0; i--) { + auto out = conditional_index_part2_cuda(m_y_symbol[i], m_y_size[i], m_size_ptr); + m_y_to_encode_size[i] = *m_size_ptr; + total_symbol_count += *m_size_ptr; + CUDA_CHECK(cudaMemcpyAsync(m_y_to_encode[i]->data(), out.data_ptr(), + (*m_size_ptr) * sizeof(int16_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + } + CUDA_CHECK(cudaStreamSynchronize(at::cuda::getCurrentCUDAStream())); + + m_entropy_coder_parallel = compute_ec_parallel(total_symbol_count); + m_entropy_encoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + + // Encode in reverse order (3,2,1,0) to match Python + for (int i = 3; i >= 0; i--) { + m_entropy_encoder.encode_y(m_y_to_encode[i], m_y_to_encode_size[i]); + } + + auto t = tensor_to_vector_1d(m_z_hat_io); + m_entropy_encoder.encode_z(t, m_qp * g_ch_z, g_ch_z); + m_entropy_encoder.flush(); + } else if (m_pending_work == DMCWorkType::DecodeZ) { + m_entropy_decoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + m_entropy_decoder.set_stream(m_bit_stream, m_bit_stream_size); + const int z_num = g_ch_z * m_z_height * m_z_width; + m_entropy_decoder.decode_z(z_num, m_qp * g_ch_z, g_ch_z); + + auto z_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_z_hat_io.data_ptr(), z_cpu->data(), + z_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_z_ready, at::cuda::getCurrentCUDAStream())); + } else if (m_pending_work == DMCWorkType::DecodeY) { + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + auto out = conditional_index_part2_cuda(m_y_indexes, m_y_indexes_size, m_size_ptr); + const int y_num = *m_size_ptr; + CUDA_CHECK(cudaMemcpyAsync(m_y_to_decode->data(), out.data_ptr(), + y_num * sizeof(uint8_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + + m_entropy_decoder.decode_y(m_y_to_decode, y_num); + + auto y_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_y_decoded.data_ptr(), y_cpu->data(), + y_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_y_ready, at::cuda::getCurrentCUDAStream())); + } else { + assert(false); + } + + { + std::lock_guard lk_result(m_mutex_result); + m_result_ready = true; + } + m_cv_result.notify_one(); + } +} + +void DMCHTLProxy::add_ref_feature_from_frame(const at::Tensor& frame, const bool apply_adaptor) +{ + pre_allocate_tensors(frame); + // must NOT use cuda graph becase frame.data_ptr() is non-const + m_feature_i = pixel_unshuffle_cuda(frame, 8, m_feature_i); + if (apply_adaptor) { + m_memory = m_feature_adaptor_i.forward(m_feature_i); + m_ctx = m_feature_extractor.forward(m_memory); + } + m_memory_has_value = apply_adaptor; +} + +py::tuple DMCHTLProxy::compress(const at::Tensor& x, const int qp, const bool reset_feature_memory, + const int padding_b, const int padding_r) +{ + m_result_ready = false; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + // must NOT use cuda graph becase x.data_ptr() is non-const + m_enc_unshuffle_out = pad_and_unshuffle_8_cuda(x, padding_b, padding_r, m_enc_unshuffle_out); + + // ----------- start of lambda_enc_0 ----------- + auto lambda_enc_0 = [&](const int qp) { + // need to output [m_z_hat_io, m_y_symbol[0..3], m_y_size[0..3]] for cpu thread + auto y = m_encoder.forward(m_cat_encoder, m_q_encoder[qp]); + auto y_pad = pad_for_y(y, m_y_pad); + auto z = m_hyper_encoder.forward(y_pad); + std::tie(m_z_hat, m_z_hat_io) = round_z_cuda(z, m_z_hat, m_z_hat_io); + m_temporal_input = multiply_with_broadcast_cuda(m_memory, m_q_feature[qp], m_temporal_input); + m_temporal_params = m_temporal_prior_encoder.forward(m_temporal_input); + m_hyper_params_pad4 = m_hyper_decoder.forward(m_z_hat); + m_hyper_params = crop_hyper_params(m_hyper_params_pad4, m_temporal_params.size(2), + m_temporal_params.size(3), m_hyper_params); + m_common_params = m_y_prior_fusion.forward(m_cat_prior_fusion); + + auto [q_dec, scales, means] = chunk_tensors_3(m_common_params); + y = divide_with_clamp_min_inplace_cuda(y, q_dec); + + const int sm = get_gpu_sm(); + m_reduced_params = conv1x1_bias(sm, m_common_params, m_y_spatial_prior_reduction.weight, + m_y_spatial_prior_reduction.bias, m_reduced_params); + + // Step 0: process with mask_0 + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_0, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[0], m_y_size[0], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[0], m_y_size[0], m_y_num); + + // copy y_hat to y_hat_so_far (first 256 channels of m_cat_spatial_prior_adaptor) + m_y_hat_so_far.copy_(m_y_hat); + + // Step 1: adaptor_1 → spatial_prior → chunk2 → new scales, means + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_1.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_1, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[1], m_y_size[1], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[1], m_y_size[1], m_y_num); + + // y_hat_so_far += y_hat_1 + m_y_hat_so_far.add_(m_y_hat); + + // Step 2: adaptor_2 → spatial_prior → chunk2 → new scales, means + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_2.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_2, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[2], m_y_size[2], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[2], m_y_size[2], m_y_num); + + // y_hat_so_far += y_hat_2 + m_y_hat_so_far.add_(m_y_hat); + + // Step 3: adaptor_3 → spatial_prior → chunk2 → final add_and_multiply + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_3.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_3, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[3], m_y_size[3], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[3], m_y_size[3], m_y_num); + + // y_hat_final = add_and_multiply_with_clamp_min_inplace(y_hat_3, y_hat_so_far, q_dec) + // swap args so result is in m_y_hat (decoder's pre-allocated input) + m_y_hat = add_and_multiply_with_clamp_min_inplace_cuda(m_y_hat, m_y_hat_so_far, q_dec); + }; + + run(lambda_enc_0, m_gexec_enc_0, m_qp); + // ------------ end of lambda_enc_0 ------------ + + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::Encode; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_enc_1 ----------- + auto lambda_enc_1 = [&](const int qp, const bool reset_feature_memory) { + m_feature_p = m_decoder.forward(m_y_hat, m_cat_decoder, m_q_decoder[qp]); + add_ref_feature_and_apply_adaptor(m_feature_p, reset_feature_memory); + }; + + run(lambda_enc_1, m_gexec_enc_1, m_qp, reset_feature_memory); + // ------------ end of lambda_enc_1 ------------ + + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (m_result_ready) { + return py::make_tuple(m_entropy_encoder.get_encoded_stream(), m_entropy_coder_parallel); + } + return py::make_tuple(py::array_t(0), 1); +} + +std::vector DMCHTLProxy::decompress(const py::array_t& bit_stream, + const int qp, const int height, const int width, + const int entropy_coder_parallel, + const bool reset_feature_memory) +{ + m_result_ready = false; + m_entropy_coder_parallel = entropy_coder_parallel; + py::buffer_info bit_stream_buf = bit_stream.request(); + m_bit_stream = static_cast(bit_stream_buf.ptr); + m_bit_stream_size = static_cast(bit_stream.size()); + m_z_height = (height + 63) / 64; + m_z_width = (width + 63) / 64; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeZ; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_dec_0 ----------- + auto lambda_dec_0 = [&](const int qp, const bool memory_has_value) { + apply_feature_adaptor(memory_has_value); + m_temporal_input = multiply_with_broadcast_cuda(m_memory, m_q_feature[qp], m_temporal_input); + m_temporal_params = m_temporal_prior_encoder.forward(m_temporal_input); + }; + + run(lambda_dec_0, m_gexec_dec_0, m_qp, m_memory_has_value); + // ------------ end of lambda_dec_0 ------------ + + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (!m_result_ready) { + return std::vector(); + } + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_z_ready)); + + at::Tensor q_dec; + at::Tensor scales; + at::Tensor means; + // ----------- start of lambda_dec_1 ----------- + auto lambda_dec_1 = [&]() { + m_z_hat = int8_to_dtype_cuda(m_z_hat_io, m_dtype, g_ch_z, m_z_height, m_z_width, m_z_hat); + m_hyper_params_pad4 = m_hyper_decoder.forward(m_z_hat); + m_hyper_params = crop_hyper_params(m_hyper_params_pad4, m_temporal_params.size(2), + m_temporal_params.size(3), m_hyper_params); + m_common_params = m_y_prior_fusion.forward(m_cat_prior_fusion); + + const int sm = get_gpu_sm(); + m_reduced_params = conv1x1_bias(sm, m_common_params, m_y_spatial_prior_reduction.weight, + m_y_spatial_prior_reduction.bias, m_reduced_params); + + m_ctx = m_feature_extractor.forward(m_memory); + + std::tie(q_dec, scales, means) = chunk_tensors_3(m_common_params); + // Step 0: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_0, m_y_indexes_skip_cond, m_y_indexes_num); + }; + + run(lambda_dec_1, m_gexec_dec_1); + // ------------ end of lambda_dec_1 ------------ + + // Step 0: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_2 ----------- + auto lambda_dec_2 = [&]() { + // Step 0: recover + restore + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + m_y_hat_so_far = restore_y_4x_cuda(m_y_q_r, means, m_mask_0, m_y_hat_so_far); + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_1.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + // Step 1: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_1, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_2, m_gexec_dec_2); + // ------------ end of lambda_dec_2 ------------ + + // Step 1: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_3 ----------- + auto lambda_dec_3 = [&]() { + // Step 1: recover + restore + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + restore_y_4x_and_add_inplace_cuda(m_y_q_r, means, m_mask_1, m_y_hat_so_far); + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_2.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + // Step 2: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_2, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_3, m_gexec_dec_3); + // ------------ end of lambda_dec_3 ------------ + + // Step 2: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_4 ----------- + auto lambda_dec_4 = [&]() { + // Step 2: recover + restore + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + restore_y_4x_and_add_inplace_cuda(m_y_q_r, means, m_mask_2, m_y_hat_so_far); + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_3.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + // Step 3: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_3, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_4, m_gexec_dec_4); + // ------------ end of lambda_dec_4 ------------ + + // Step 3: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_5 ----------- + auto lambda_dec_5 = [&](const int qp) { + // Step 3: recover + restore (QP-dependent due to q_dec) + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + m_y_hat = restore_y_4x_cuda(m_y_q_r, means, m_mask_3, m_y_hat); + // swap args so result is in m_y_hat (decoder's pre-allocated input) + m_y_hat = add_and_multiply_with_clamp_min_inplace_cuda(m_y_hat, m_y_hat_so_far, q_dec); + // decoder + recon_head + m_feature_p = m_decoder.forward(m_y_hat, m_cat_decoder, m_q_decoder[qp]); + std::tie(m_x_hat, m_feature_i) = + m_recon_head.forward(m_feature_p); // m_feature_i is also updated for reset purpose; + }; + + run(lambda_dec_5, m_gexec_dec_5, m_qp); + // ------------ end of lambda_dec_5 ------------ + + m_memory_has_value = !reset_feature_memory; // host operation. must be outside of cuda graph + + return m_x_hat; +} + +void DMCHTLProxy::set_param(const std::map& state_dict, + const float skip_threshold) +{ + m_device = state_dict.at("q_decoder").device(); + m_dtype = state_dict.at("q_decoder").scalar_type(); + auto q_encoder = state_dict.at("q_encoder"); + auto q_decoder = state_dict.at("q_decoder"); + auto q_feature = state_dict.at("q_feature"); + for (int i = 0; i < g_qp_num; i++) { + m_q_encoder[i] = q_encoder.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_decoder[i] = q_decoder.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_feature[i] = q_feature.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + } + m_encoder.set_param(get_submodule_state_dict(state_dict, "encoder.")); + m_hyper_encoder.set_param(get_submodule_state_dict(state_dict, "hyper_encoder.")); + m_temporal_prior_encoder.set_param( + get_submodule_state_dict(state_dict, "temporal_prior_encoder.")); + m_hyper_decoder.set_param(get_submodule_state_dict(state_dict, "hyper_decoder.")); + m_y_prior_fusion.set_param(get_submodule_state_dict(state_dict, "y_prior_fusion.")); + m_y_spatial_prior_reduction.set_param(state_dict, "y_spatial_prior_reduction."); + m_y_spatial_prior_adaptor_1.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_1.")); + m_y_spatial_prior_adaptor_2.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_2.")); + m_y_spatial_prior_adaptor_3.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_3.")); + m_y_spatial_prior.set_param(get_submodule_state_dict(state_dict, "y_spatial_prior.")); + m_decoder.set_param(get_submodule_state_dict(state_dict, "decoder.")); + m_feature_adaptor_i.set_param(get_submodule_state_dict(state_dict, "feature_adaptor_i.")); + m_feature_adaptor_m.set_param(get_submodule_state_dict(state_dict, "feature_adaptor_m.")); + m_feature_extractor.set_param(get_submodule_state_dict(state_dict, "feature_extractor.")); + m_recon_head.set_param(get_submodule_state_dict(state_dict, "recon_head.")); + + m_skip_threshold = skip_threshold; + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); + + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); +} + +void DMCHTLProxy::add_ref_feature_and_apply_adaptor(const at::Tensor& feature, + const bool reset_feature_memory) +{ + if (reset_feature_memory) { + auto out = m_recon_head.forward_reset(feature); + m_memory = m_feature_adaptor_i.forward(out); + } else { + m_memory = m_feature_adaptor_m.forward(m_cat_feature_adaptor_m); + } + m_ctx = m_feature_extractor.forward(m_memory); +} + +void DMCHTLProxy::apply_feature_adaptor(const bool memory_has_value) +{ + if (memory_has_value) { + m_memory = m_feature_adaptor_m.forward(m_cat_feature_adaptor_m); + } else { + m_memory = m_feature_adaptor_i.forward(m_feature_i); + } +} + +void DMCHTLProxy::clear_cuda_graph() +{ + for (int i = 0; i < g_qp_num; ++i) { + destroy_cuda_graph_exec(m_gexec_enc_0[i]); + for (int j = 0; j < 2; ++j) { + destroy_cuda_graph_exec(m_gexec_enc_1[i][j]); + } + for (int j = 0; j < 2; ++j) { + destroy_cuda_graph_exec(m_gexec_dec_0[i][j]); + } + destroy_cuda_graph_exec(m_gexec_dec_5[i]); + } + destroy_cuda_graph_exec(m_gexec_dec_1); + destroy_cuda_graph_exec(m_gexec_dec_2); + destroy_cuda_graph_exec(m_gexec_dec_3); + destroy_cuda_graph_exec(m_gexec_dec_4); +} + +at::Tensor DMCHTLProxy::decode_y_step_build_index(const at::Tensor& scales, const at::Tensor& mask, + at::Tensor& skip_cond_out, at::Tensor& indexes_num_out) +{ + m_scales_r = single_part_for_reading_4x_cuda(scales, mask, m_scales_r); + std::tie(m_y_indexes_prev, skip_cond_out) = build_index_dec_cuda( + m_scales_r, m_skip_threshold, at::nullopt, 0, m_y_indexes_prev, skip_cond_out); + std::tie(m_y_indexes, m_y_indexes_size, indexes_num_out) = conditional_index_part1_cuda( + m_y_indexes_prev, skip_cond_out, m_y_indexes, m_y_indexes_size, indexes_num_out); + return m_y_indexes; +} + +std::tuple DMCHTLProxy::get_mask_4x(const at::Tensor& y) +{ + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + auto m = at::ones({ 1, C / 4, H, W }, y.options().dtype(at::kBool)); + auto m0 = get_one_mask(torch::tensor({ { 1, 0 }, { 0, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m1 = get_one_mask(torch::tensor({ { 0, 1 }, { 0, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m2 = get_one_mask(torch::tensor({ { 0, 0 }, { 1, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m3 = get_one_mask(torch::tensor({ { 0, 0 }, { 0, 1 } }, y.options().dtype(at::kBool)), H, W); + + auto mask_0 = + at::cat({ m * m0, m * m1, m * m2, m * m3 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_1 = + at::cat({ m * m3, m * m2, m * m1, m * m0 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_2 = + at::cat({ m * m2, m * m3, m * m0, m * m1 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_3 = + at::cat({ m * m1, m * m0, m * m3, m * m2 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + + return { mask_0, mask_1, mask_2, mask_3 }; +} + +void DMCHTLProxy::pre_allocate_tensors(const at::Tensor& frame) +{ + int H = frame.size(2); + int W = frame.size(3); + H = (H + 16 - 1) / 16 * 16; + W = (W + 16 - 1) / 16 * 16; + const int H8 = H / 8; + const int W8 = W / 8; + if (m_H8 == H8 && m_W8 == W8) { + return; + } + + m_H8 = H8; + m_W8 = W8; + clear_cuda_graph(); + g_tensor_pool.clear(H8, W8); + + auto options = frame.options().memory_format(at::MemoryFormat::ChannelsLast); + const int H16 = H8 / 2; + const int W16 = W8 / 2; + auto [padR, padB] = get_padding_size(H16, W16, 4); + const int H16_pad4 = H16 + padB; + const int W16_pad4 = W16 + padR; + const int H64 = H16_pad4 / 4; + const int W64 = W16_pad4 / 4; + + const std::vector feature_i_shape = { 1, g_ch_src_d_intra, H8, W8 }; + const std::vector memory_shape = { 1, g_ch_m, H8, W8 }; + const std::vector y_shape = { 1, g_ch_y, H16, W16 }; + const std::vector y_pad_shape = { 1, g_ch_y, H16_pad4, W16_pad4 }; + const std::vector z_shape = { 1, g_ch_z, H64, W64 }; + + auto y = at::empty(y_shape, options); + + // pre allocate masks + std::tie(m_mask_0, m_mask_1, m_mask_2, m_mask_3) = get_mask_4x(y); + + // pre allocate entropy coder buffers + const int y_quarter_numel = g_ch_y / 4 * H16 * W16; + for (int i = 0; i < 4; i++) { + m_y_to_encode[i] = std::make_shared>(y_quarter_numel); + } + + // + // pre allocate concatenated tensors + // + + // 1. deal with m_cat_encoder, m_cat_decoder, m_enc_unshuffle_out, m_decoder_up_out, and m_ctx + assert(g_ch_src_d > g_ch_d); + at::Tensor tensor_placeholder; + m_cat_encoder = at::empty({ 1, g_ch_src_d + g_ch_d, H8, W8 }, options); + std::tie(tensor_placeholder, m_cat_decoder) = + split_tensors_2(m_cat_encoder, g_ch_src_d - g_ch_d, g_ch_d * 2); + std::tie(tensor_placeholder, m_decoder_up_out, m_ctx) = + split_tensors_3(m_cat_encoder, g_ch_src_d - g_ch_d, g_ch_d, g_ch_d); + std::tie(m_enc_unshuffle_out, m_ctx) = split_tensors_2(m_cat_encoder, g_ch_src_d, g_ch_d); + + // 2. deal with m_cat_feature_adaptor_m, m_memory, and m_feature_p + m_cat_feature_adaptor_m = at::empty({ 1, g_ch_m + g_ch_d, H8, W8 }, options); + std::tie(m_memory, m_feature_p) = split_tensors_2(m_cat_feature_adaptor_m, g_ch_m, g_ch_d); + + // 3. deal with m_cat_prior_fusion, m_hyper_params, and m_temporal_params + m_cat_prior_fusion = at::empty({ 1, g_ch_y * 3, H16, W16 }, options); + std::tie(m_hyper_params, m_temporal_params) = + split_tensors_2(m_cat_prior_fusion, g_ch_y, g_ch_y * 2); + m_hyper_params_pad4 = (padR == 0 && padB == 0) ? m_hyper_params : at::empty(y_pad_shape, options); + + // 4. deal with m_cat_spatial_prior_adaptor, m_y_hat_so_far, and m_reduced_params + m_cat_spatial_prior_adaptor = at::empty({ 1, g_ch_y * 2, H16, W16 }, options); + std::tie(m_y_hat_so_far, m_reduced_params) = + split_tensors_2(m_cat_spatial_prior_adaptor, g_ch_y, g_ch_y); + + // pre allocate other tensors + m_feature_i = at::empty(feature_i_shape, options); + m_temporal_input = at::empty(memory_shape, options); + + m_z_hat = at::empty(z_shape, options.dtype(at::kHalf)); + m_z_hat_io = at::empty(z_shape, options.dtype(at::kChar)); + + m_spatial_prior_out = at::empty({ 1, g_ch_y * 2, H16, W16 }, options); + m_y_q = at::empty_like(y); + m_y_hat = at::empty_like(y); + m_s_hat = at::empty_like(y); + + m_y_q_w = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_s_w = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_y_symbol_prev = at::empty({ y_quarter_numel }, y.options().dtype(at::kShort)); + m_skip_cond = at::empty({ y_quarter_numel }, y.options().dtype(at::kBool)); + { + const int block_num_quarter = + (y_quarter_numel + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + m_y_num = + at::empty({ block_num_quarter, COND_KERNEL_THREAD_NUM1 }, y.options().dtype(at::kInt)); + } + for (int i = 0; i < 4; i++) { + m_y_symbol[i] = at::empty({ y_quarter_numel }, y.options().dtype(at::kShort)); + m_y_size[i] = at::empty({ 1 }, y.options().dtype(at::kInt)); + } + + // decompress-only buffers + m_y_q_r = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_scales_r = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_y_decoded = at::empty({ y_quarter_numel }, y.options().dtype(at::kChar)); + m_y_to_decode = std::make_shared>(y_quarter_numel); + m_y_indexes = at::empty({ y_quarter_numel }, y.options().dtype(at::kByte)); + m_y_indexes_prev = at::empty_like(m_y_indexes); + m_y_indexes_skip_cond = at::empty({ y_quarter_numel }, y.options().dtype(at::kBool)); + { + const int block_num_quarter = + (y_quarter_numel + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + m_y_indexes_size = at::empty({ 1 }, y.options().dtype(at::kInt)); + m_y_indexes_num = + at::empty({ block_num_quarter, COND_KERNEL_THREAD_NUM1 }, y.options().dtype(at::kInt)); + } + + // pre allocate modules + m_y = m_encoder.pre_allocate_tensors(m_cat_encoder); + m_y_pad = (padR == 0 && padB == 0) ? m_y : at::empty(y_pad_shape, options); + auto enc_z = m_hyper_encoder.pre_allocate_tensors(m_y_pad); + m_temporal_params = + m_temporal_prior_encoder.pre_allocate_tensors(m_temporal_input, m_temporal_params); + m_hyper_params_pad4 = m_hyper_decoder.pre_allocate_tensors(m_z_hat, m_hyper_params_pad4); + m_common_params = m_y_prior_fusion.pre_allocate_tensors(m_cat_prior_fusion); + auto adaptor_out = + m_y_spatial_prior_adaptor_1.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true); + m_y_spatial_prior_adaptor_2.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true, adaptor_out); + m_y_spatial_prior_adaptor_3.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true, adaptor_out); + m_spatial_prior_out = m_y_spatial_prior.pre_allocate_tensors(adaptor_out, m_spatial_prior_out); + m_feature_p = m_decoder.pre_allocate_tensors(m_y_hat, m_decoder_up_out, m_cat_decoder, m_feature_p); + m_memory = m_feature_adaptor_i.pre_allocate_tensors(m_feature_i, m_memory); + m_memory = m_feature_adaptor_m.pre_allocate_tensors(m_cat_feature_adaptor_m, m_memory); + m_ctx = m_feature_extractor.pre_allocate_tensors(m_memory, m_ctx); + m_feature_i = m_recon_head.pre_allocate_tensors( + m_feature_p, m_feature_i); // the recon is not used in cuda graph, only use feature for reset +} diff --git a/src/layers/extensions/inference/dmc_htl_proxy.h b/src/layers/extensions/inference/dmc_htl_proxy.h new file mode 100644 index 0000000..9b18396 --- /dev/null +++ b/src/layers/extensions/inference/dmc_htl_proxy.h @@ -0,0 +1,375 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "dmc_common.h" + +class DMCHTLDecoderProxy { +public: + DMCHTLDecoderProxy() = default; + ~DMCHTLDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& conv1_input, const at::Tensor& quant); + at::Tensor forward_part1(const at::Tensor& x); + at::Tensor forward_part2(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x, at::Tensor& up_out_buf, + at::Tensor& conv1_input_buf, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + SubpelConv2xProxy m_up; + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv12; + DepthConvBlockProxy m_conv13; + DepthConvBlockProxy m_conv14; + DepthConvBlockProxy m_conv15; + DepthConvBlockProxy m_conv16; + DepthConvBlockProxy m_conv17; + DepthConvBlockProxy m_conv18; + DepthConvBlockProxy m_conv19; + DepthConvBlockProxy m_conv1a; + + // for cuda graphs + at::Tensor m_conv1_out; +}; + +class DMCHTLEncoderProxy { +public: + DMCHTLEncoderProxy() = default; + ~DMCHTLEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv12; + DepthConvBlockProxy m_conv13; + DepthConvBlockProxy m_conv14; + DepthConvBlockProxy m_conv15; + DepthConvBlockProxy m_conv16; + at::Tensor m_down_weight; + at::Tensor m_down_bias; + + // for cuda graph + at::Tensor m_down_out; +}; + +class DMCHTLFeatureAdaptorIProxy { +public: + DMCHTLFeatureAdaptorIProxy() = default; + ~DMCHTLFeatureAdaptorIProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; +}; + +class DMCHTLFeatureAdaptorMProxy { +public: + DMCHTLFeatureAdaptorMProxy() = default; + ~DMCHTLFeatureAdaptorMProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; + DepthConvBlockProxy m_conv4; + DepthConvBlockProxy m_conv5; + DepthConvBlockProxy m_conv6; + DepthConvBlockProxy m_conv7; + DepthConvBlockProxy m_conv8; + DepthConvBlockProxy m_conv9; +}; + +class DMCHTLFeatureExtractorProxy { +public: + DMCHTLFeatureExtractorProxy() = default; + ~DMCHTLFeatureExtractorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; +}; + +class DMCHTLHyperDecoderProxy { +public: + DMCHTLHyperDecoderProxy() = default; + ~DMCHTLHyperDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockUpsampleProxy m_conv0; + ResidualBlockUpsampleProxy m_conv1; + DepthConvBlockProxy m_conv2; +}; + +class DMCHTLHyperEncoderProxy { +public: + DMCHTLHyperEncoderProxy() = default; + ~DMCHTLHyperEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + ResidualBlockWithStride2Proxy m_conv1; + ResidualBlockWithStride2Proxy m_conv2; +}; + +class DMCHTLPriorFusionProxy { +public: + DMCHTLPriorFusionProxy() = default; + ~DMCHTLPriorFusionProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graphs + at::Tensor m_conv3_out; +}; + +class DMCHTLReconHeadProxy { +public: + static constexpr int g_frame_delay = 8; + DMCHTLReconHeadProxy() = default; + ~DMCHTLReconHeadProxy() = default; + + at::Tensor forward_reset(const at::Tensor& x); + std::tuple, at::Tensor> forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0[g_frame_delay]; + DepthConvBlockProxy m_conv1[g_frame_delay]; + DepthConvBlockProxy m_conv2[g_frame_delay]; + DepthConvBlockProxy m_conv3[g_frame_delay]; + DepthConvBlockProxy m_conv4[g_frame_delay]; + at::Tensor m_head_weight[g_frame_delay]; + at::Tensor m_head_bias[g_frame_delay]; + + // for cuda graphs + at::Tensor m_head_out[g_frame_delay]; + at::Tensor m_shuffle_out[g_frame_delay]; +}; + +class DMCHTLSpatialPriorProxy { +public: + DMCHTLSpatialPriorProxy() = default; + ~DMCHTLSpatialPriorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graphs + at::Tensor m_conv3_out; +}; + +class DMCHTLTemporalPriorEncoderProxy { +public: + DMCHTLTemporalPriorEncoderProxy() = default; + ~DMCHTLTemporalPriorEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockWithStride2Proxy m_conv; +}; + +class DMCHTLProxy : public DMCCommon { +public: + static constexpr int g_frame_delay = 8; + static constexpr int g_ch_src_d_intra = 3 * 8 * 8; + static constexpr int g_ch_src_d = g_ch_src_d_intra * g_frame_delay; + static constexpr int g_ch_y = 256; + static constexpr int g_ch_z = 128; + static constexpr int g_ch_d = 512; + static constexpr int g_ch_m = 512; + static constexpr int g_ch_recon = 256; + + DMCHTLProxy(); + ~DMCHTLProxy(); + +private: + void worker(); + +public: + void add_ref_feature_from_frame(const at::Tensor& frame, const bool apply_adaptor); + py::tuple compress(const at::Tensor& x, const int qp, const bool reset_feature_memory, + const int padding_b, const int padding_r); + std::vector decompress(const py::array_t& bit_stream, const int qp, + const int height, const int width, + const int entropy_coder_parallel, + const bool reset_feature_memory); + void set_param(const std::map& state_dict, const float skip_threshold); + +private: + void add_ref_feature_and_apply_adaptor(const at::Tensor& feature, const bool reset_feature_memory); + void apply_feature_adaptor(const bool memory_none); + + // cuda graph related + void clear_cuda_graph(); + + // helper functions + at::Tensor decode_y_step_build_index(const at::Tensor& scales, const at::Tensor& mask, + at::Tensor& skip_cond_out, at::Tensor& indexes_num_out); + std::tuple get_mask_4x(const at::Tensor& y); + + // compress and decompress components + void pre_allocate_tensors(const at::Tensor& frame); + +private: + at::Tensor m_q_encoder[g_qp_num]; + at::Tensor m_q_decoder[g_qp_num]; + at::Tensor m_q_feature[g_qp_num]; + + DMCHTLEncoderProxy m_encoder; + DMCHTLHyperEncoderProxy m_hyper_encoder; + DMCHTLTemporalPriorEncoderProxy m_temporal_prior_encoder; + DMCHTLHyperDecoderProxy m_hyper_decoder; + DMCHTLPriorFusionProxy m_y_prior_fusion; + ConvParam m_y_spatial_prior_reduction; + DepthConvBlockProxy m_y_spatial_prior_adaptor_1; + DepthConvBlockProxy m_y_spatial_prior_adaptor_2; + DepthConvBlockProxy m_y_spatial_prior_adaptor_3; + DMCHTLSpatialPriorProxy m_y_spatial_prior; + DMCHTLDecoderProxy m_decoder; + DMCHTLFeatureAdaptorIProxy m_feature_adaptor_i; + DMCHTLFeatureAdaptorMProxy m_feature_adaptor_m; + DMCHTLFeatureExtractorProxy m_feature_extractor; + DMCHTLReconHeadProxy m_recon_head; + + float m_skip_threshold{ 0.f }; + + bool m_finish{ false }; + bool m_result_ready{ false }; + std::thread m_thread; + std::mutex m_mutex_result; + std::mutex m_mutex_pending; + std::condition_variable m_cv_pending; + std::condition_variable m_cv_result; + bool m_pending{ false }; + DMCWorkType m_pending_work; + + uint8_t* m_bit_stream{ nullptr }; + int m_bit_stream_size{ 0 }; + int m_z_width{ 0 }; + int m_z_height{ 0 }; + + cudaEvent_t m_event_y; + cudaEvent_t m_event_y_ready; + cudaEvent_t m_event_z_ready; + int* m_size_ptr{ nullptr }; + + int m_qp{ 0 }; + std::shared_ptr> m_y_to_encode[4]{ nullptr }; + int m_y_to_encode_size[4]{ 0 }; + + at::ScalarType m_dtype; + at::Device m_device{ at::kCUDA }; + + // for cuda graph + int m_H8{ 0 }; + int m_W8{ 0 }; + cudaGraphExec_t m_gexec_enc_0[g_qp_num]{ nullptr }; + cudaGraphExec_t m_gexec_enc_1[g_qp_num][2]{ nullptr }; + cudaGraphExec_t m_gexec_dec_0[g_qp_num][2]{ nullptr }; + cudaGraphExec_t m_gexec_dec_1{ nullptr }; + cudaGraphExec_t m_gexec_dec_2{ nullptr }; + cudaGraphExec_t m_gexec_dec_3{ nullptr }; + cudaGraphExec_t m_gexec_dec_4{ nullptr }; + cudaGraphExec_t m_gexec_dec_5[g_qp_num]{ nullptr }; + bool m_memory_has_value{ true }; + at::Tensor m_mask_0; + at::Tensor m_mask_1; + at::Tensor m_mask_2; + at::Tensor m_mask_3; + at::Tensor m_enc_unshuffle_out; + at::Tensor m_feature_i; // output of image frame unshuffle or recon_head reset + at::Tensor m_feature_p; // output of decoder + at::Tensor m_memory; // output of both feature_adaptor_i and feature_adaptor_m + at::Tensor m_ctx; + at::Tensor m_temporal_input; + at::Tensor m_temporal_params; + at::Tensor m_y; + at::Tensor m_y_pad; + at::Tensor m_hyper_params; + at::Tensor m_hyper_params_pad4; + at::Tensor m_common_params; // no allocation + at::Tensor m_z_hat; + at::Tensor m_z_hat_io; + at::Tensor m_spatial_prior_out; + at::Tensor m_reduced_params; + at::Tensor m_y_q; + at::Tensor m_y_hat; + at::Tensor m_s_hat; + at::Tensor m_y_hat_so_far; // view into m_cat_spatial_prior_adaptor + at::Tensor m_y_q_w; + at::Tensor m_s_w; + at::Tensor m_y_symbol[4]; + at::Tensor m_y_symbol_prev; + at::Tensor m_skip_cond; + at::Tensor m_y_size[4]; + at::Tensor m_y_num; + // decode-only + at::Tensor m_scales_r; + at::Tensor m_y_q_r; + at::Tensor m_y_decoded; + at::Tensor m_y_indexes; + at::Tensor m_y_indexes_prev; + at::Tensor m_y_indexes_skip_cond; + at::Tensor m_y_indexes_size; + at::Tensor m_y_indexes_num; + std::shared_ptr> m_y_to_decode; + at::Tensor m_decoder_up_out; + std::vector m_x_hat; // no allocation. length: g_frame_delay + + // 5 concatenated tensors + at::Tensor m_cat_encoder; + at::Tensor m_cat_decoder; + at::Tensor m_cat_feature_adaptor_m; + at::Tensor m_cat_prior_fusion; + at::Tensor m_cat_spatial_prior_adaptor; +}; diff --git a/src/layers/extensions/inference/dmc_hts_proxy.cpp b/src/layers/extensions/inference/dmc_hts_proxy.cpp new file mode 100644 index 0000000..a78b8fc --- /dev/null +++ b/src/layers/extensions/inference/dmc_hts_proxy.cpp @@ -0,0 +1,1000 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include + +#include "common_cpp.h" +#include "cuda_check.h" +#include "def_cutlass.h" +#include "def_elementwise.h" +#include "dmc_hts_proxy.h" +#include "memory_pool.h" + +at::Tensor DMCHTSDecoderProxy::forward(const at::Tensor& x, const at::Tensor& conv1_input, + const at::Tensor& quant) +{ + auto out = forward_part1(x); + out = forward_part2(conv1_input, quant); + return out; +} + +at::Tensor DMCHTSDecoderProxy::forward_part1(const at::Tensor& x) +{ + return m_up.forward(x); +} + +at::Tensor DMCHTSDecoderProxy::forward_part2(const at::Tensor& x, const at::Tensor& quant) +{ + auto out = m_conv10.forward(x); + out = m_conv11.forward(out); + out = m_conv12.forward(out); + out = m_conv13.forward(out); + out = m_conv14.forward(out); + out = m_conv15.forward(out); + out = m_conv16.forward(out, quant); + return out; +} + +at::Tensor DMCHTSDecoderProxy::pre_allocate_tensors(at::Tensor& x, at::Tensor& up_out_buf, + at::Tensor& conv1_input_buf, + const at::Tensor& out_buf) +{ + m_up.pre_allocate_tensors(x, up_out_buf); + m_conv1_out = out_buf; + auto out = m_conv10.pre_allocate_tensors(conv1_input_buf, true); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv12.pre_allocate_tensors(out); + out = m_conv13.pre_allocate_tensors(out); + out = m_conv14.pre_allocate_tensors(out); + out = m_conv15.pre_allocate_tensors(out); + out = m_conv16.pre_allocate_tensors(out, false, m_conv1_out); + + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv12.release_tensors(); + m_conv13.release_tensors(); + m_conv14.release_tensors(); + m_conv15.release_tensors(); + m_conv16.release_tensors(); + g_tensor_pool.set_reusable(m_conv1_out, false); + return m_conv1_out; +} + +void DMCHTSDecoderProxy::set_param(const std::map& state_dict) +{ + m_up.set_param(get_submodule_state_dict(state_dict, "up.")); + m_conv10.set_param(get_submodule_state_dict(state_dict, "conv1.0.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "conv1.1.")); + m_conv12.set_param(get_submodule_state_dict(state_dict, "conv1.2.")); + m_conv13.set_param(get_submodule_state_dict(state_dict, "conv1.3.")); + m_conv14.set_param(get_submodule_state_dict(state_dict, "conv1.4.")); + m_conv15.set_param(get_submodule_state_dict(state_dict, "conv1.5.")); + m_conv16.set_param(get_submodule_state_dict(state_dict, "conv1.6.")); +} + +at::Tensor DMCHTSEncoderProxy::forward(const at::Tensor& x, const at::Tensor& quant) +{ + const int sm = get_gpu_sm(); + auto out = m_conv10.forward(x); + out = m_conv11.forward(out); + out = m_conv12.forward(out); + out = m_conv13.forward(out); + out = m_conv14.forward(out); + out = m_conv15.forward(out, quant); + out = conv_bias(sm, out, m_down_weight, m_down_bias, 2, m_down_out); + return out; +} + +at::Tensor DMCHTSEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_down_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_down = m_down_weight.size(0); + m_down_out = g_tensor_pool.empty({ 1, ch_down, H / 2, W / 2 }, options); + auto out = m_conv10.pre_allocate_tensors(x, true); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv12.pre_allocate_tensors(out); + out = m_conv13.pre_allocate_tensors(out); + out = m_conv14.pre_allocate_tensors(out); + out = m_conv15.pre_allocate_tensors(out); + + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv12.release_tensors(); + m_conv13.release_tensors(); + m_conv14.release_tensors(); + m_conv15.release_tensors(); + return m_down_out; +} + +void DMCHTSEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv10.set_param(get_submodule_state_dict(state_dict, "conv1.0.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "conv1.1.")); + m_conv12.set_param(get_submodule_state_dict(state_dict, "conv1.2.")); + m_conv13.set_param(get_submodule_state_dict(state_dict, "conv1.3.")); + m_conv14.set_param(get_submodule_state_dict(state_dict, "conv1.4.")); + m_conv15.set_param(get_submodule_state_dict(state_dict, "conv1.5.")); + m_down_weight = state_dict.at("down.weight"); + m_down_bias = state_dict.at("down.bias"); +} + +at::Tensor DMCHTSFeatureAdaptorIProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + return out; +} + +at::Tensor DMCHTSFeatureAdaptorIProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTSFeatureAdaptorIProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); +} + +at::Tensor DMCHTSFeatureAdaptorMProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + out = m_conv4.forward(out); + out = m_conv5.forward(out); + return out; +} + +at::Tensor DMCHTSFeatureAdaptorMProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out); + out = m_conv4.pre_allocate_tensors(out); + out = m_conv5.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + m_conv4.release_tensors(); + m_conv5.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTSFeatureAdaptorMProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); + m_conv4.set_param(get_submodule_state_dict(state_dict, "conv.4.")); + m_conv5.set_param(get_submodule_state_dict(state_dict, "conv.5.")); +} + +at::Tensor DMCHTSFeatureExtractorProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + out = m_conv4.forward(out); + return out; +} + +at::Tensor DMCHTSFeatureExtractorProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out); + out = m_conv4.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + m_conv4.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTSFeatureExtractorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); + m_conv4.set_param(get_submodule_state_dict(state_dict, "conv.4.")); +} + +at::Tensor DMCHTSHyperDecoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCHTSHyperDecoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTSHyperDecoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0."), false); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), false); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); +} + +at::Tensor DMCHTSHyperEncoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCHTSHyperEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTSHyperEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), false); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2."), false); +} + +at::Tensor DMCHTSPriorFusionProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCHTSPriorFusionProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_conv3_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_conv3 = m_conv3_weight.size(0); + m_conv3_out = g_tensor_pool.empty({ 1, ch_conv3, H, W }, options); + // x is a cat parameter, will be further used + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCHTSPriorFusionProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +std::tuple, at::Tensor> DMCHTSReconHeadProxy::forward(const at::Tensor& x) +{ + at::Tensor for_reset; + const int sm = get_gpu_sm(); + auto all_out = std::vector(g_frame_delay); + at::Tensor common_out; + for (int i = 0; i < g_frame_delay; i++) { + if (i % 2 == 0) { + common_out = m_conv1_0[i / 2].forward(x); + } + auto out = m_conv2_0[i].forward(common_out); + out = m_conv2_1[i].forward(out); + out = m_conv2_2[i].forward(out); + out = conv1x1_bias(sm, out, m_head_weight[i], m_head_bias[i], m_head_out[i]); + if (i == g_frame_delay - 1) { + for_reset = out; + } + out = pixel_shuffle_8_cuda(out, true, m_shuffle_out[i]); + all_out[i] = out; + } + return { all_out, for_reset }; +} + +at::Tensor DMCHTSReconHeadProxy::forward_reset(const at::Tensor& x) +{ + constexpr int conv1_index = g_frame_delay / 2 - 1; + constexpr int conv2_index = g_frame_delay - 1; + const int sm = get_gpu_sm(); + auto out = m_conv1_0[conv1_index].forward(x); + out = m_conv2_0[conv2_index].forward(out); + out = m_conv2_1[conv2_index].forward(out); + out = m_conv2_2[conv2_index].forward(out); + out = conv1x1_bias(sm, out, m_head_weight[conv2_index], m_head_bias[conv2_index], + m_head_out[conv2_index]); + return out; +} + +at::Tensor DMCHTSReconHeadProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_head_weight[0].options().memory_format(at::MemoryFormat::ChannelsLast); + const int C = m_head_weight[0].size(0); + at::Tensor common_out; + for (int i = 0; i < g_frame_delay; i++) { + if (i % 2 == 0) { + common_out = m_conv1_0[i / 2].pre_allocate_tensors(x, true); // must not modify! + } + if (i != g_frame_delay - 1) { + m_head_out[i] = g_tensor_pool.empty({ 1, C, H, W }, options); + } else { + m_head_out[i] = out_buf; + } + m_shuffle_out[i] = at::empty({ 1, C / 64, H * 8, W * 8 }, options); + + auto out = m_conv2_0[i].pre_allocate_tensors(common_out, true); // must not modify! + out = m_conv2_1[i].pre_allocate_tensors(out); + out = m_conv2_2[i].pre_allocate_tensors(out); + if (i % 2 == 1) { + m_conv1_0[i / 2].release_tensors(); + g_tensor_pool.release(common_out); + } + if (i != g_frame_delay - 1) { + g_tensor_pool.release(m_head_out[i]); + } + m_conv2_0[i].release_tensors(); + m_conv2_1[i].release_tensors(); + m_conv2_2[i].release_tensors(); + } + return m_head_out[g_frame_delay - 1]; +} + +void DMCHTSReconHeadProxy::set_param(const std::map& state_dict) +{ + for (int i = 0; i < g_frame_delay / 2; i++) { + m_conv1_0[i].set_param( + get_submodule_state_dict(state_dict, "conv1." + std::to_string(i) + ".0.")); + } + for (int i = 0; i < g_frame_delay; i++) { + m_conv2_0[i].set_param( + get_submodule_state_dict(state_dict, "conv2." + std::to_string(i) + ".0.")); + m_conv2_1[i].set_param( + get_submodule_state_dict(state_dict, "conv2." + std::to_string(i) + ".1.")); + m_conv2_2[i].set_param( + get_submodule_state_dict(state_dict, "conv2." + std::to_string(i) + ".2.")); + m_head_weight[i] = state_dict.at("conv2." + std::to_string(i) + ".3.weight"); + m_head_bias[i] = state_dict.at("conv2." + std::to_string(i) + ".3.bias"); + } +} + +at::Tensor DMCHTSSpatialPriorProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCHTSSpatialPriorProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + m_conv3_out = out_buf; + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCHTSSpatialPriorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +at::Tensor DMCHTSTemporalPriorEncoderProxy::forward(const at::Tensor& x) +{ + return m_conv.forward(x); +} + +at::Tensor DMCHTSTemporalPriorEncoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv.pre_allocate_tensors(x, out_buf); + m_conv.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCHTSTemporalPriorEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv.set_param(get_submodule_state_dict(state_dict, "conv."), false); +} + +DMCHTSProxy::DMCHTSProxy() +{ + CUDA_CHECK(cudaMallocHost((void**)&m_size_ptr, sizeof(int))); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_z_ready, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y_ready, cudaEventDisableTiming)); + m_thread = std::thread(&DMCHTSProxy::worker, this); +} + +DMCHTSProxy::~DMCHTSProxy() +{ + { + std::lock_guard lk(m_mutex_pending); + m_finish = true; + } + m_cv_pending.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } + cudaEventDestroy(m_event_y); + cudaEventDestroy(m_event_z_ready); + cudaEventDestroy(m_event_y_ready); + cudaFreeHost(m_size_ptr); + + clear_cuda_graph(); +} + +void DMCHTSProxy::add_ref_feature_from_frame(const at::Tensor& frame, const bool apply_adaptor) +{ + pre_allocate_tensors(frame); + // must NOT use cuda graph becase frame.data_ptr() is non-const + m_feature_i = pixel_unshuffle_cuda(frame, 8, m_feature_i); + if (apply_adaptor) { + m_memory = m_feature_adaptor_i.forward(m_feature_i); + m_ctx = m_feature_extractor.forward(m_memory); + } + m_memory_has_value = apply_adaptor; +} + +py::tuple DMCHTSProxy::compress(const at::Tensor& x, const int qp, const bool reset_feature_memory, + const int padding_b, const int padding_r) +{ + m_result_ready = false; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + // must NOT use cuda graph becase x.data_ptr() is non-const + m_enc_unshuffle_out = pad_and_unshuffle_8_cuda(x, padding_b, padding_r, m_enc_unshuffle_out); + + // ----------- start of lambda_enc_0 ----------- + auto lambda_enc_0 = [&](const int qp) { + // need to output [m_z_hat_io, m_y_symbol, m_y_size] for cpu thread + auto y = m_encoder.forward(m_cat_encoder, m_q_encoder[qp]); + auto y_pad = pad_for_y(y, m_y_pad); + auto z = m_hyper_encoder.forward(y_pad); + std::tie(m_z_hat, m_z_hat_io) = round_z_cuda(z, m_z_hat, m_z_hat_io); + m_temporal_input = multiply_with_broadcast_cuda(m_memory, m_q_feature[qp], m_temporal_input); + m_temporal_params = m_temporal_prior_encoder.forward(m_temporal_input); + m_hyper_params_pad4 = m_hyper_decoder.forward(m_z_hat); + m_hyper_params = crop_hyper_params(m_hyper_params_pad4, m_temporal_params.size(2), + m_temporal_params.size(3), m_hyper_params); + m_common_params = m_y_prior_fusion.forward(m_cat_prior_fusion); + + auto [q_dec, scales, means] = chunk_tensors_3(m_common_params); + y = divide_with_clamp_min_inplace_cuda(y, q_dec); + + const int sm = get_gpu_sm(); + m_reduced_params = conv1x1_bias(sm, m_common_params, m_y_spatial_prior_reduction.weight, + m_y_spatial_prior_reduction.bias, m_reduced_params); + std::tie(m_y_q, m_y_hat) = process_with_mask_no_scale_cuda( + y, scales, means, m_mask_0, m_skip_threshold, 0, m_y_q, m_y_hat); + + m_means = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_1.forward(m_cat_spatial_prior_adaptor)); + std::tie(m_y_q, m_y_hat) = process_with_mask_no_scale_add_inplace_cuda( + y, scales, m_means, m_mask_1, m_y_q, m_y_hat, m_skip_threshold, 0); + + m_means = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_2.forward(m_cat_spatial_prior_adaptor)); + std::tie(m_y_q, m_y_hat) = process_with_mask_no_scale_add_inplace_cuda( + y, scales, m_means, m_mask_2, m_y_q, m_y_hat, m_skip_threshold, 0); + + m_means = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_3.forward(m_cat_spatial_prior_adaptor)); + std::tie(m_y_q, m_y_hat) = process_with_mask_no_scale_add_and_multiply_inplace_cuda( + y, scales, m_means, m_mask_3, m_y_q, m_y_hat, q_dec, m_skip_threshold, 0); + + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q, scales, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol, m_y_size, m_y_num) = + conditional_index_part1_cuda(m_y_symbol_prev, m_skip_cond, m_y_symbol, m_y_size, m_y_num); + }; + + run(lambda_enc_0, m_gexec_enc_0, m_qp); + // ------------ end of lambda_enc_0 ------------ + + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::Encode; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_enc_1 ----------- + auto lambda_enc_1 = [&](const int qp, const bool reset_feature_memory) { + m_feature_p = m_decoder.forward(m_y_hat, m_cat_decoder, m_q_decoder[qp]); + add_ref_feature_and_apply_adaptor(m_feature_p, reset_feature_memory); + }; + + run(lambda_enc_1, m_gexec_enc_1, m_qp, reset_feature_memory); + // ------------ end of lambda_enc_1 ------------ + + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (m_result_ready) { + return py::make_tuple(m_entropy_encoder.get_encoded_stream(), m_entropy_coder_parallel); + } + return py::make_tuple(py::array_t(0), 1); +} + +std::vector DMCHTSProxy::decompress(const py::array_t& bit_stream, + const int qp, const int height, const int width, + const int entropy_coder_parallel, + const bool reset_feature_memory) +{ + m_result_ready = false; + m_entropy_coder_parallel = entropy_coder_parallel; + py::buffer_info bit_stream_buf = bit_stream.request(); + m_bit_stream = static_cast(bit_stream_buf.ptr); + m_bit_stream_size = static_cast(bit_stream.size()); + m_z_height = (height + 63) / 64; + m_z_width = (width + 63) / 64; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeZ; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_dec_0 ----------- + auto lambda_dec_0 = [&](const int qp, const bool memory_has_value) { + apply_feature_adaptor(memory_has_value); + m_temporal_input = multiply_with_broadcast_cuda(m_memory, m_q_feature[qp], m_temporal_input); + m_temporal_params = m_temporal_prior_encoder.forward(m_temporal_input); + }; + + run(lambda_dec_0, m_gexec_dec_0, m_qp, m_memory_has_value); + // ------------ end of lambda_dec_0 ------------ + + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (!m_result_ready) { + return std::vector(); + } + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_z_ready)); + + at::Tensor q_dec; + at::Tensor scales; + at::Tensor means; + // ----------- start of lambda_dec_1 ----------- + auto lambda_dec_1 = [&]() { + // need to output [m_y_indexes, m_y_size] for cpu thread + m_z_hat = int8_to_dtype_cuda(m_z_hat_io, m_dtype, g_ch_z, m_z_height, m_z_width, m_z_hat); + m_hyper_params_pad4 = m_hyper_decoder.forward(m_z_hat); + m_hyper_params = crop_hyper_params(m_hyper_params_pad4, m_temporal_params.size(2), + m_temporal_params.size(3), m_hyper_params); + m_common_params = m_y_prior_fusion.forward(m_cat_prior_fusion); + std::tie(q_dec, scales, means) = chunk_tensors_3(m_common_params); + std::tie(m_y_indexes_prev, m_skip_cond) = build_index_dec_cuda( + scales, m_skip_threshold, at::nullopt, 0, m_y_indexes_prev, m_skip_cond); + std::tie(m_y_indexes, m_y_size, m_y_num) = + conditional_index_part1_cuda(m_y_indexes_prev, m_skip_cond, m_y_indexes, m_y_size, m_y_num); + }; + + run(lambda_dec_1, m_gexec_dec_1); + // ------------ end of lambda_dec_1 ------------ + + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_dec_2 ----------- + auto lambda_dec_2 = [&]() { m_ctx = m_feature_extractor.forward(m_memory); }; + + run(lambda_dec_2, m_gexec_dec_2); + // ------------ end of lambda_dec_2 ------------ + + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (!m_result_ready) { + return std::vector(); + } + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_3 ----------- + auto lambda_dec_3 = [&](const int qp) { + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_skip_cond, m_y_num, + m_dtype, m_y_q_r); + m_y_hat = restore_y_cuda(m_y_q_r, means, m_mask_0, m_y_hat); + + const int sm = get_gpu_sm(); + m_reduced_params = conv1x1_bias(sm, m_common_params, m_y_spatial_prior_reduction.weight, + m_y_spatial_prior_reduction.bias, m_reduced_params); + + m_means = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_1.forward(m_cat_spatial_prior_adaptor)); + m_y_hat = restore_y_and_add_inplace_cuda(m_y_q_r, m_means, m_mask_1, m_y_hat); + + m_means = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_2.forward(m_cat_spatial_prior_adaptor)); + m_y_hat = restore_y_and_add_inplace_cuda(m_y_q_r, m_means, m_mask_2, m_y_hat); + + m_means = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_3.forward(m_cat_spatial_prior_adaptor)); + + m_y_hat = restore_y_and_add_multiply_inplace_cuda(m_y_q_r, m_means, m_mask_3, m_y_hat, q_dec); + + // decoder + recon_head + m_feature_p = m_decoder.forward(m_y_hat, m_cat_decoder, m_q_decoder[qp]); + std::tie(m_x_hat, m_feature_i) = + m_recon_head.forward(m_feature_p); // m_feature_i is also updated for reset purpose; + }; + + run(lambda_dec_3, m_gexec_dec_3, m_qp); + // ------------ end of lambda_dec_3 ------------ + + m_memory_has_value = !reset_feature_memory; // host operation. must be outside of cuda graph + + return m_x_hat; +} + +void DMCHTSProxy::set_param(const std::map& state_dict, + const float skip_threshold) +{ + m_device = state_dict.at("q_decoder").device(); + m_dtype = state_dict.at("q_decoder").scalar_type(); + auto q_encoder = state_dict.at("q_encoder"); + auto q_decoder = state_dict.at("q_decoder"); + auto q_feature = state_dict.at("q_feature"); + for (int i = 0; i < g_qp_num; i++) { + m_q_encoder[i] = q_encoder.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_decoder[i] = q_decoder.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_feature[i] = q_feature.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + } + m_encoder.set_param(get_submodule_state_dict(state_dict, "encoder.")); + m_hyper_encoder.set_param(get_submodule_state_dict(state_dict, "hyper_encoder.")); + m_temporal_prior_encoder.set_param( + get_submodule_state_dict(state_dict, "temporal_prior_encoder.")); + m_hyper_decoder.set_param(get_submodule_state_dict(state_dict, "hyper_decoder.")); + m_y_prior_fusion.set_param(get_submodule_state_dict(state_dict, "y_prior_fusion.")); + m_y_spatial_prior_reduction.set_param(state_dict, "y_spatial_prior_reduction."); + m_y_spatial_prior_adaptor_1.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_1.")); + m_y_spatial_prior_adaptor_2.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_2.")); + m_y_spatial_prior_adaptor_3.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_3.")); + m_y_spatial_prior.set_param(get_submodule_state_dict(state_dict, "y_spatial_prior.")); + m_decoder.set_param(get_submodule_state_dict(state_dict, "decoder.")); + m_feature_adaptor_i.set_param(get_submodule_state_dict(state_dict, "feature_adaptor_i.")); + m_feature_adaptor_m.set_param(get_submodule_state_dict(state_dict, "feature_adaptor_m.")); + m_feature_extractor.set_param(get_submodule_state_dict(state_dict, "feature_extractor.")); + m_recon_head.set_param(get_submodule_state_dict(state_dict, "recon_head.")); + + m_skip_threshold = skip_threshold; + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); + + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); +} + +void DMCHTSProxy::worker() +{ + at::cuda::CUDAStream high_priority_stream = at::cuda::getStreamFromPool(true); + at::cuda::CUDAStreamGuard guard(high_priority_stream); + + while (!m_finish) { + std::unique_lock lk(m_mutex_pending); + m_cv_pending.wait(lk, [this] { return m_pending || m_finish; }); + if (m_finish) { + break; + } + m_pending = false; + lk.unlock(); + + if (m_pending_work == DMCWorkType::Encode) { + m_entropy_encoder.reset(); + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + + auto out = conditional_index_part2_cuda(m_y_symbol, m_y_size, m_size_ptr); + CUDA_CHECK(cudaMemcpyAsync(m_y_to_encode->data(), out.data_ptr(), + (*m_size_ptr) * sizeof(int16_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaStreamSynchronize(at::cuda::getCurrentCUDAStream())); + m_entropy_coder_parallel = compute_ec_parallel(*m_size_ptr); + m_entropy_encoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + m_entropy_encoder.encode_y(m_y_to_encode, *m_size_ptr); + + auto t = tensor_to_vector_1d(m_z_hat_io); + m_entropy_encoder.encode_z(t, m_qp * g_ch_z, g_ch_z); + m_entropy_encoder.flush(); + } else if (m_pending_work == DMCWorkType::DecodeZ) { + m_entropy_decoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + m_entropy_decoder.set_stream(m_bit_stream, m_bit_stream_size); + const int z_num = g_ch_z * m_z_height * m_z_width; + m_entropy_decoder.decode_z(z_num, m_qp * g_ch_z, g_ch_z); + + auto z_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_z_hat_io.data_ptr(), z_cpu->data(), + z_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_z_ready, at::cuda::getCurrentCUDAStream())); + } else if (m_pending_work == DMCWorkType::DecodeY) { + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + auto out = conditional_index_part2_cuda(m_y_indexes, m_y_size, m_size_ptr); + const int y_num = *m_size_ptr; + CUDA_CHECK(cudaMemcpyAsync(m_y_to_decode->data(), out.data_ptr(), + y_num * sizeof(uint8_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + + m_entropy_decoder.decode_y(m_y_to_decode, y_num); + + auto y_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_y_decoded.data_ptr(), y_cpu->data(), + y_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_y_ready, at::cuda::getCurrentCUDAStream())); + } else { + assert(false); + } + + { + std::lock_guard lk_result(m_mutex_result); + m_result_ready = true; + } + m_cv_result.notify_one(); + } +} + +void DMCHTSProxy::add_ref_feature_and_apply_adaptor(const at::Tensor& feature, + const bool reset_feature_memory) +{ + if (reset_feature_memory) { + auto out = m_recon_head.forward_reset(feature); + m_memory = m_feature_adaptor_i.forward(out); + } else { + m_memory = m_feature_adaptor_m.forward(m_cat_feature_adaptor_m); + } + m_ctx = m_feature_extractor.forward(m_memory); +} + +void DMCHTSProxy::apply_feature_adaptor(const bool memory_has_value) +{ + if (memory_has_value) { + m_memory = m_feature_adaptor_m.forward(m_cat_feature_adaptor_m); + } else { + m_memory = m_feature_adaptor_i.forward(m_feature_i); + } +} + +void DMCHTSProxy::clear_cuda_graph() +{ + for (int i = 0; i < g_qp_num; ++i) { + destroy_cuda_graph_exec(m_gexec_enc_0[i]); + for (int j = 0; j < 2; ++j) { + destroy_cuda_graph_exec(m_gexec_enc_1[i][j]); + } + destroy_cuda_graph_exec(m_gexec_dec_3[i]); + for (int j = 0; j < 2; ++j) { + destroy_cuda_graph_exec(m_gexec_dec_0[i][j]); + } + } + destroy_cuda_graph_exec(m_gexec_dec_1); + destroy_cuda_graph_exec(m_gexec_dec_2); +} + +std::tuple DMCHTSProxy::get_mask_4x(const at::Tensor& y) +{ + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + auto m = at::ones({ 1, C / 4, H, W }, y.options().dtype(at::kBool)); + auto m0 = get_one_mask(torch::tensor({ { 1, 0 }, { 0, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m1 = get_one_mask(torch::tensor({ { 0, 1 }, { 0, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m2 = get_one_mask(torch::tensor({ { 0, 0 }, { 1, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m3 = get_one_mask(torch::tensor({ { 0, 0 }, { 0, 1 } }, y.options().dtype(at::kBool)), H, W); + + auto mask_0 = + at::cat({ m * m0, m * m1, m * m2, m * m3 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_1 = + at::cat({ m * m3, m * m2, m * m1, m * m0 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_2 = + at::cat({ m * m2, m * m3, m * m0, m * m1 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_3 = + at::cat({ m * m1, m * m0, m * m3, m * m2 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + + return { mask_0, mask_1, mask_2, mask_3 }; +} + +void DMCHTSProxy::pre_allocate_tensors(const at::Tensor& frame) +{ + int H = frame.size(2); + int W = frame.size(3); + H = (H + 16 - 1) / 16 * 16; + W = (W + 16 - 1) / 16 * 16; + const int H8 = H / 8; + const int W8 = W / 8; + if (m_H8 == H8 && m_W8 == W8) { + return; + } + + m_H8 = H8; + m_W8 = W8; + clear_cuda_graph(); + g_tensor_pool.clear(H8, W8); + + auto options = frame.options().memory_format(at::MemoryFormat::ChannelsLast); + const int H16 = H8 / 2; + const int W16 = W8 / 2; + auto [padR, padB] = get_padding_size(H16, W16, 4); + const int H16_pad4 = H16 + padB; + const int W16_pad4 = W16 + padR; + const int H64 = H16_pad4 / 4; + const int W64 = W16_pad4 / 4; + + const std::vector feature_i_shape = { 1, g_ch_src_d_intra, H8, W8 }; + const std::vector memory_shape = { 1, g_ch_m, H8, W8 }; + const std::vector y_shape = { 1, g_ch_y, H16, W16 }; + const std::vector y_pad_shape = { 1, g_ch_y, H16_pad4, W16_pad4 }; + const std::vector z_shape = { 1, g_ch_z, H64, W64 }; + + auto y = at::empty(y_shape, options); + + // pre allocate tensors + std::tie(m_mask_0, m_mask_1, m_mask_2, m_mask_3) = get_mask_4x(y); + m_y_decoded = at::empty({ y.numel() }, y.options().dtype(at::kChar)); + m_y_to_decode = std::make_shared>(y.numel()); + m_y_to_encode = std::make_shared>(y.numel()); + + // + // pre allocate concatenated tensors + // + + // 1. deal with m_cat_encoder, m_cat_decoder, m_enc_unshuffle_out, m_decoder_up_out, and m_ctx + assert(g_ch_src_d > g_ch_d); + at::Tensor tensor_placeholder; + m_cat_encoder = at::empty({ 1, g_ch_src_d + g_ch_d, H8, W8 }, options); + std::tie(tensor_placeholder, m_cat_decoder) = + split_tensors_2(m_cat_encoder, g_ch_src_d - g_ch_d, g_ch_d * 2); + std::tie(tensor_placeholder, m_decoder_up_out, m_ctx) = + split_tensors_3(m_cat_encoder, g_ch_src_d - g_ch_d, g_ch_d, g_ch_d); + std::tie(m_enc_unshuffle_out, m_ctx) = split_tensors_2(m_cat_encoder, g_ch_src_d, g_ch_d); + + // 2. deal with m_cat_feature_adaptor_m, m_memory, and m_feature_p + m_cat_feature_adaptor_m = at::empty({ 1, g_ch_m + g_ch_d, H8, W8 }, options); + std::tie(m_memory, m_feature_p) = split_tensors_2(m_cat_feature_adaptor_m, g_ch_m, g_ch_d); + + // 3. deal with m_cat_prior_fusion, m_hyper_params, and m_temporal_params + m_cat_prior_fusion = at::empty({ 1, g_ch_y * 3, H16, W16 }, options); + std::tie(m_hyper_params, m_temporal_params) = + split_tensors_2(m_cat_prior_fusion, g_ch_y, g_ch_y * 2); + m_hyper_params_pad4 = (padR == 0 && padB == 0) ? m_hyper_params : at::empty(y_pad_shape, options); + + // 4. deal with m_cat_spatial_prior_adaptor, m_y_hat, and m_reduced_params + m_cat_spatial_prior_adaptor = at::empty({ 1, g_ch_y * 2, H16, W16 }, options); + std::tie(m_y_hat, m_reduced_params) = split_tensors_2(m_cat_spatial_prior_adaptor, g_ch_y, g_ch_y); + + // pre allocate other tensors + m_feature_i = at::empty(feature_i_shape, options); + m_temporal_input = at::empty(memory_shape, options); + + m_z_hat = at::empty(z_shape, options.dtype(at::kHalf)); + m_z_hat_io = at::empty(z_shape, options.dtype(at::kChar)); + + m_means = at::empty_like(y); + m_y_q = at::empty_like(y); + m_y_q_r = at::empty_like(y); + + m_y_symbol = at::empty({ y.numel() }, y.options().dtype(at::kShort)); + m_y_symbol_prev = at::empty_like(m_y_symbol); + m_y_indexes = at::empty({ y.numel() }, y.options().dtype(at::kByte)); + m_y_indexes_prev = at::empty_like(m_y_indexes); + m_skip_cond = at::empty({ y.numel() }, y.options().dtype(at::kBool)); + + const int block_num = (y.numel() + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + m_y_size = at::empty({ 1 }, y.options().dtype(at::kInt)); + m_y_num = at::empty({ block_num, COND_KERNEL_THREAD_NUM1 }, y.options().dtype(at::kInt)); + + // pre allocate modules + m_y = m_encoder.pre_allocate_tensors(m_cat_encoder); + m_y_pad = (padR == 0 && padB == 0) ? m_y : at::empty(y_pad_shape, options); + m_hyper_encoder.pre_allocate_tensors(m_y_pad); + m_temporal_prior_encoder.pre_allocate_tensors(m_temporal_input, m_temporal_params); + m_hyper_decoder.pre_allocate_tensors(m_z_hat, m_hyper_params_pad4); + m_common_params = m_y_prior_fusion.pre_allocate_tensors(m_cat_prior_fusion); + auto adaptor_out = + m_y_spatial_prior_adaptor_1.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true); + m_y_spatial_prior_adaptor_2.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true, adaptor_out); + m_y_spatial_prior_adaptor_3.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true, adaptor_out); + m_y_spatial_prior.pre_allocate_tensors(adaptor_out, m_means); + m_decoder.pre_allocate_tensors(m_y_hat, m_decoder_up_out, m_cat_decoder, m_feature_p); + m_feature_adaptor_i.pre_allocate_tensors(m_feature_i, m_memory); + m_feature_adaptor_m.pre_allocate_tensors(m_cat_feature_adaptor_m, m_memory); + m_feature_extractor.pre_allocate_tensors(m_memory, m_ctx); + m_recon_head.pre_allocate_tensors( + m_feature_p, m_feature_i); // the recon is not used in cuda graph, only use feature for reset +} diff --git a/src/layers/extensions/inference/dmc_hts_proxy.h b/src/layers/extensions/inference/dmc_hts_proxy.h new file mode 100644 index 0000000..e9d428e --- /dev/null +++ b/src/layers/extensions/inference/dmc_hts_proxy.h @@ -0,0 +1,355 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "dmc_common.h" + +class DMCHTSDecoderProxy { +public: + DMCHTSDecoderProxy() = default; + ~DMCHTSDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& conv1_input, const at::Tensor& quant); + at::Tensor forward_part1(const at::Tensor& x); + at::Tensor forward_part2(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x, at::Tensor& up_out_buf, + at::Tensor& conv1_input_buf, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + SubpelConv2xProxy m_up; + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv12; + DepthConvBlockProxy m_conv13; + DepthConvBlockProxy m_conv14; + DepthConvBlockProxy m_conv15; + DepthConvBlockProxy m_conv16; + + // for cuda graphs + at::Tensor m_conv1_out; +}; + +class DMCHTSEncoderProxy { +public: + DMCHTSEncoderProxy() = default; + ~DMCHTSEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv12; + DepthConvBlockProxy m_conv13; + DepthConvBlockProxy m_conv14; + DepthConvBlockProxy m_conv15; + at::Tensor m_down_weight; + at::Tensor m_down_bias; + + // for cuda graph + at::Tensor m_down_out; +}; + +class DMCHTSFeatureAdaptorIProxy { +public: + DMCHTSFeatureAdaptorIProxy() = default; + ~DMCHTSFeatureAdaptorIProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; +}; + +class DMCHTSFeatureAdaptorMProxy { +public: + DMCHTSFeatureAdaptorMProxy() = default; + ~DMCHTSFeatureAdaptorMProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; + DepthConvBlockProxy m_conv4; + DepthConvBlockProxy m_conv5; +}; + +class DMCHTSFeatureExtractorProxy { +public: + DMCHTSFeatureExtractorProxy() = default; + ~DMCHTSFeatureExtractorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; + DepthConvBlockProxy m_conv4; +}; + +class DMCHTSHyperDecoderProxy { +public: + DMCHTSHyperDecoderProxy() = default; + ~DMCHTSHyperDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockUpsampleProxy m_conv0; + ResidualBlockUpsampleProxy m_conv1; + DepthConvBlockProxy m_conv2; +}; + +class DMCHTSHyperEncoderProxy { +public: + DMCHTSHyperEncoderProxy() = default; + ~DMCHTSHyperEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + ResidualBlockWithStride2Proxy m_conv1; + ResidualBlockWithStride2Proxy m_conv2; +}; + +class DMCHTSPriorFusionProxy { +public: + DMCHTSPriorFusionProxy() = default; + ~DMCHTSPriorFusionProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graphs + at::Tensor m_conv3_out; +}; + +class DMCHTSReconHeadProxy { +public: + static constexpr int g_frame_delay = 8; + DMCHTSReconHeadProxy() = default; + ~DMCHTSReconHeadProxy() = default; + + std::tuple, at::Tensor> forward(const at::Tensor& x); + at::Tensor forward_reset(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv1_0[g_frame_delay / 2]; + DepthConvBlockProxy m_conv2_0[g_frame_delay]; + DepthConvBlockProxy m_conv2_1[g_frame_delay]; + DepthConvBlockProxy m_conv2_2[g_frame_delay]; + at::Tensor m_head_weight[g_frame_delay]; + at::Tensor m_head_bias[g_frame_delay]; + + // for cuda graphs + at::Tensor m_head_out[g_frame_delay]; + at::Tensor m_shuffle_out[g_frame_delay]; +}; + +class DMCHTSSpatialPriorProxy { +public: + DMCHTSSpatialPriorProxy() = default; + ~DMCHTSSpatialPriorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graphs + at::Tensor m_conv3_out; +}; + +class DMCHTSTemporalPriorEncoderProxy { +public: + DMCHTSTemporalPriorEncoderProxy() = default; + ~DMCHTSTemporalPriorEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockWithStride2Proxy m_conv; +}; + +class DMCHTSProxy : public DMCCommon { +public: + static constexpr int g_frame_delay = 8; + static constexpr int g_ch_src_d_intra = 3 * 8 * 8; + static constexpr int g_ch_src_d = g_ch_src_d_intra * g_frame_delay; + static constexpr int g_ch_y = 256; + static constexpr int g_ch_z = 128; + static constexpr int g_ch_d = 512; + static constexpr int g_ch_m = 512; + static constexpr int g_ch_recon = 256; + + DMCHTSProxy(); + ~DMCHTSProxy(); + + void add_ref_feature_from_frame(const at::Tensor& frame, const bool apply_adaptor); + py::tuple compress(const at::Tensor& x, const int qp, const bool reset_feature_memory, + const int padding_b, const int padding_r); + std::vector decompress(const py::array_t& bit_stream, const int qp, + const int height, const int width, + const int entropy_coder_parallel, + const bool reset_feature_memory); + void set_param(const std::map& state_dict, const float skip_threshold); + +private: + void worker(); + +public: +private: + // compress and decompress components + void add_ref_feature_and_apply_adaptor(const at::Tensor& feature, const bool reset_feature_memory); + void apply_feature_adaptor(const bool memory_none); + + // cuda graph related + void clear_cuda_graph(); + + // helper functions + std::tuple get_mask_4x(const at::Tensor& y); + + void pre_allocate_tensors(const at::Tensor& frame); + +private: + at::Tensor m_q_encoder[g_qp_num]; + at::Tensor m_q_decoder[g_qp_num]; + at::Tensor m_q_feature[g_qp_num]; + + DMCHTSEncoderProxy m_encoder; + DMCHTSHyperEncoderProxy m_hyper_encoder; + DMCHTSTemporalPriorEncoderProxy m_temporal_prior_encoder; + DMCHTSHyperDecoderProxy m_hyper_decoder; + DMCHTSPriorFusionProxy m_y_prior_fusion; + ConvParam m_y_spatial_prior_reduction; + DepthConvBlockProxy m_y_spatial_prior_adaptor_1; + DepthConvBlockProxy m_y_spatial_prior_adaptor_2; + DepthConvBlockProxy m_y_spatial_prior_adaptor_3; + DMCHTSSpatialPriorProxy m_y_spatial_prior; + DMCHTSDecoderProxy m_decoder; + DMCHTSFeatureAdaptorIProxy m_feature_adaptor_i; + DMCHTSFeatureAdaptorMProxy m_feature_adaptor_m; + DMCHTSFeatureExtractorProxy m_feature_extractor; + DMCHTSReconHeadProxy m_recon_head; + + float m_skip_threshold{ 0.f }; + + bool m_finish{ false }; + bool m_result_ready{ false }; + std::thread m_thread; + std::mutex m_mutex_result; + std::mutex m_mutex_pending; + std::condition_variable m_cv_pending; + std::condition_variable m_cv_result; + bool m_pending{ false }; + DMCWorkType m_pending_work; + + uint8_t* m_bit_stream{ nullptr }; + int m_bit_stream_size{ 0 }; + int m_z_width{ 0 }; + int m_z_height{ 0 }; + + cudaEvent_t m_event_y; + cudaEvent_t m_event_z_ready; + cudaEvent_t m_event_y_ready; + int* m_size_ptr{ nullptr }; + + int m_qp{ 0 }; + std::shared_ptr> m_y_to_encode{ nullptr }; + std::shared_ptr> m_y_to_decode{ nullptr }; + + at::ScalarType m_dtype; + at::Device m_device{ at::kCUDA }; + + // for cuda graph + int m_H8{ 0 }; + int m_W8{ 0 }; + cudaGraphExec_t m_gexec_enc_0[g_qp_num]{ nullptr }; + cudaGraphExec_t m_gexec_enc_1[g_qp_num][2]{ nullptr }; + cudaGraphExec_t m_gexec_dec_0[g_qp_num][2]{ nullptr }; + cudaGraphExec_t m_gexec_dec_1{ nullptr }; + cudaGraphExec_t m_gexec_dec_2{ nullptr }; + cudaGraphExec_t m_gexec_dec_3[g_qp_num]{ nullptr }; + bool m_memory_has_value{ true }; + at::Tensor m_mask_0; + at::Tensor m_mask_1; + at::Tensor m_mask_2; + at::Tensor m_mask_3; + at::Tensor m_enc_unshuffle_out; + at::Tensor m_feature_i; // output of image frame unshuffle or recon_head reset + at::Tensor m_feature_p; // output of decoder + at::Tensor m_memory; // output of both feature_adaptor_i and feature_adaptor_m + at::Tensor m_ctx; + at::Tensor m_temporal_input; + at::Tensor m_temporal_params; + at::Tensor m_y; + at::Tensor m_y_pad; + at::Tensor m_hyper_params; + at::Tensor m_hyper_params_pad4; + at::Tensor m_common_params; // no allocation + at::Tensor m_z_hat; + at::Tensor m_z_hat_io; + at::Tensor m_means; + at::Tensor m_reduced_params; + at::Tensor m_y_q; + at::Tensor m_y_q_r; // only for decompress + at::Tensor m_y_hat; + at::Tensor m_y_symbol; + at::Tensor m_y_symbol_prev; + at::Tensor m_y_indexes; + at::Tensor m_y_indexes_prev; + at::Tensor m_skip_cond; + at::Tensor m_y_decoded; + at::Tensor m_y_size; + at::Tensor m_y_num; + at::Tensor m_decoder_up_out; + std::vector m_x_hat; // no allocation. length: g_frame_delay + + // 5 concatenated tensors + at::Tensor m_cat_encoder; + at::Tensor m_cat_decoder; + at::Tensor m_cat_feature_adaptor_m; + at::Tensor m_cat_prior_fusion; + at::Tensor m_cat_spatial_prior_adaptor; +}; diff --git a/src/layers/extensions/inference/dmc_ld_proxy.cpp b/src/layers/extensions/inference/dmc_ld_proxy.cpp new file mode 100644 index 0000000..4dfe494 --- /dev/null +++ b/src/layers/extensions/inference/dmc_ld_proxy.cpp @@ -0,0 +1,862 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include + +#include "common_cpp.h" +#include "cuda_check.h" +#include "def_cutlass.h" +#include "def_elementwise.h" +#include "dmc_ld_proxy.h" +#include "memory_pool.h" + +at::Tensor DMCLDDecoderProxy::forward(const at::Tensor& x, const at::Tensor& conv1_input, + const at::Tensor& quant) +{ + auto out = forward_part1(x); + out = forward_part2(conv1_input, quant); + return out; +} + +at::Tensor DMCLDDecoderProxy::forward_part1(const at::Tensor& x) +{ + return m_up.forward(x); +} + +at::Tensor DMCLDDecoderProxy::forward_part2(const at::Tensor& x, const at::Tensor& quant) +{ + const int sm = get_gpu_sm(); + auto out = m_conv10.forward(x); + out = m_conv11.forward(out); + out = m_conv12.forward(out); + out = conv1x1_bias_with_quant(sm, out, m_conv2_weight, m_conv2_bias, quant, m_conv2_out); + return out; +} + +at::Tensor DMCLDDecoderProxy::pre_allocate_tensors(at::Tensor& x, at::Tensor& up_out_buf, + at::Tensor& conv1_input_buf, + const at::Tensor& out_buf) +{ + m_up.pre_allocate_tensors(x, up_out_buf); + m_conv2_out = out_buf; + auto out = m_conv10.pre_allocate_tensors(conv1_input_buf, true); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv12.pre_allocate_tensors(out); + + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv12.release_tensors(); + return m_conv2_out; +} + +void DMCLDDecoderProxy::set_param(const std::map& state_dict) +{ + m_up.set_param(get_submodule_state_dict(state_dict, "up.")); + m_conv10.set_param(get_submodule_state_dict(state_dict, "conv1.0.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "conv1.1.")); + m_conv12.set_param(get_submodule_state_dict(state_dict, "conv1.2.")); + m_conv2_weight = state_dict.at("conv2.weight"); + m_conv2_bias = state_dict.at("conv2.bias"); +} + +at::Tensor DMCLDEncoderProxy::forward(const at::Tensor& x, const at::Tensor& quant) +{ + const int sm = get_gpu_sm(); + auto out = m_conv10.forward(x); + out = m_conv11.forward(out); + out = m_conv2.forward(out, quant); + out = conv_bias(sm, out, m_down_weight, m_down_bias, 2, m_down_out); + return out; +} + +at::Tensor DMCLDEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_down_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_down = m_down_weight.size(0); + m_down_out = g_tensor_pool.empty({ 1, ch_down, H / 2, W / 2 }, options); + auto out = m_conv10.pre_allocate_tensors(x, true); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv2.release_tensors(); + return m_down_out; +} + +void DMCLDEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv10.set_param(get_submodule_state_dict(state_dict, "conv1.0.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "conv1.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv2.")); + m_down_weight = state_dict.at("down.weight"); + m_down_bias = state_dict.at("down.bias"); +} + +at::Tensor DMCLDFeatureAdaptorIProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + return out; +} + +at::Tensor DMCLDFeatureAdaptorIProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCLDFeatureAdaptorIProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); +} + +at::Tensor DMCLDFeatureAdaptorMProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + return out; +} + +at::Tensor DMCLDFeatureAdaptorMProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCLDFeatureAdaptorMProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); +} + +at::Tensor DMCLDFeatureExtractorProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + out = m_conv4.forward(out); + return out; +} + +at::Tensor DMCLDFeatureExtractorProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out); + out = m_conv4.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + m_conv4.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCLDFeatureExtractorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "conv.3.")); + m_conv4.set_param(get_submodule_state_dict(state_dict, "conv.4.")); +} + +at::Tensor DMCLDHyperDecoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCLDHyperDecoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out, false, out_buf); + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCLDHyperDecoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0."), false); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), false); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); +} + +at::Tensor DMCLDHyperEncoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCLDHyperEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCLDHyperEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), false); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2."), false); +} + +at::Tensor DMCLDPriorFusionProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCLDPriorFusionProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + m_conv3_out = out_buf; + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCLDPriorFusionProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +at::Tensor DMCLDReconHeadProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_head_weight, m_head_bias, m_head_out); + out = pixel_shuffle_8_cuda(out, true, m_shuffle_out); + return out; +} + +at::Tensor DMCLDReconHeadProxy::forward_reset(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_head_weight, m_head_bias, m_head_out); + return out; +} + +at::Tensor DMCLDReconHeadProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_head_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int C = m_head_weight.size(0); + m_head_out = out_buf; + m_shuffle_out = at::empty({ 1, C / 64, H * 8, W * 8 }, options); + auto out = m_conv0.pre_allocate_tensors(x, true); // must not modify! + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_shuffle_out; +} + +void DMCLDReconHeadProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_head_weight = state_dict.at("head.weight"); + m_head_bias = state_dict.at("head.bias"); +} + +at::Tensor DMCLDSpatialPriorProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = conv1x1_bias(sm, out, m_conv2_weight, m_conv2_bias, m_conv2_out); + return out; +} + +at::Tensor DMCLDSpatialPriorProxy::pre_allocate_tensors(at::Tensor& x, at::Tensor& out_buf) +{ + m_conv2_out = out_buf; + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + return m_conv2_out; +} + +void DMCLDSpatialPriorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2_weight = state_dict.at("conv.2.weight"); + m_conv2_bias = state_dict.at("conv.2.bias"); +} + +at::Tensor DMCLDTemporalPriorEncoderProxy::forward(const at::Tensor& x) +{ + return m_conv.forward(x); +} + +at::Tensor DMCLDTemporalPriorEncoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv.pre_allocate_tensors(x, out_buf); + m_conv.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCLDTemporalPriorEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv.set_param(get_submodule_state_dict(state_dict, "conv."), false); +} + +DMCLDProxy::DMCLDProxy() +{ + CUDA_CHECK(cudaMallocHost((void**)&m_size_ptr, sizeof(int))); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_z_ready, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y_ready, cudaEventDisableTiming)); + m_thread = std::thread(&DMCLDProxy::worker, this); +} + +DMCLDProxy::~DMCLDProxy() +{ + { + std::lock_guard lk(m_mutex_pending); + m_finish = true; + } + m_cv_pending.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } + cudaEventDestroy(m_event_y); + cudaEventDestroy(m_event_z_ready); + cudaEventDestroy(m_event_y_ready); + cudaFreeHost(m_size_ptr); + + clear_cuda_graph(); +} + +void DMCLDProxy::add_ref_feature_from_frame(const at::Tensor& frame, const bool apply_adaptor) +{ + pre_allocate_tensors(frame); + // must NOT use cuda graph becase frame.data_ptr() is non-const + m_feature_i = pixel_unshuffle_cuda(frame, 8, m_feature_i); + if (apply_adaptor) { + m_memory = m_feature_adaptor_i.forward(m_feature_i); + m_ctx = m_feature_extractor.forward(m_memory); + m_temporal_params = m_temporal_prior_encoder.forward(m_memory); + } + m_memory_has_value = apply_adaptor; +} + +py::tuple DMCLDProxy::compress(const at::Tensor& x, const int qp, const bool reset_feature_memory, + const int padding_b, const int padding_r) +{ + m_result_ready = false; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + // must NOT use cuda graph becase x.data_ptr() is non-const + m_enc_unshuffle_out = pad_and_unshuffle_8_cuda(x, padding_b, padding_r, m_enc_unshuffle_out); + + // ----------- start of lambda_enc_0 ----------- + auto lambda_enc_0 = [&](const int qp) { + // need to output [m_z_hat_io, m_y_symbol, m_y_size] for cpu thread + auto y = m_encoder.forward(m_cat_encoder, m_q_encoder[qp]); + auto y_pad = pad_for_y(y, m_y_pad); + auto z = m_hyper_encoder.forward(y_pad); + std::tie(m_z_hat, m_z_hat_io) = round_z_cuda(z, m_z_hat, m_z_hat_io); + m_hyper_params_pad4 = m_hyper_decoder.forward(m_z_hat); + m_hyper_params = crop_hyper_params(m_hyper_params_pad4, m_temporal_params.size(2), + m_temporal_params.size(3), m_hyper_params); + m_temporal_params = multiply_with_broadcast_cuda(m_temporal_params, m_q_feature[qp], + m_temporal_params); // inplace + m_common_params = m_y_prior_fusion.forward(m_cat_prior_fusion); + + auto [q_dec, scales, means] = chunk_tensors_3(m_common_params); + y = divide_with_clamp_min_inplace_cuda(y, q_dec); + std::tie(m_y_q, m_y_hat) = process_with_mask_no_scale_cuda( + y, scales, means, m_mask_0, m_skip_threshold, 0, m_y_q, m_y_hat); + m_means = m_y_spatial_prior.forward(m_cat_spatial_prior); + std::tie(m_y_q, m_y_hat) = process_with_mask_no_scale_add_and_multiply_inplace_cuda( + y, scales, m_means, m_mask_1, m_y_q, m_y_hat, q_dec, m_skip_threshold, 0); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q, scales, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol, m_y_size, m_y_num) = + conditional_index_part1_cuda(m_y_symbol_prev, m_skip_cond, m_y_symbol, m_y_size, m_y_num); + }; + + run(lambda_enc_0, m_gexec_enc_0, m_qp); + // ------------ end of lambda_enc_0 ------------ + + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::Encode; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_enc_1 ----------- + auto lambda_enc_1 = [&](const int qp, const bool reset_feature_memory) { + m_feature_p = m_decoder.forward(m_y_hat, m_cat_decoder, m_q_decoder[qp]); + add_ref_feature_and_apply_adaptor(m_feature_p, reset_feature_memory); + m_temporal_params = m_temporal_prior_encoder.forward(m_memory); + }; + + run(lambda_enc_1, m_gexec_enc_1, m_qp, reset_feature_memory); + // ------------ end of lambda_enc_1 ------------ + + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (m_result_ready) { + return py::make_tuple(m_entropy_encoder.get_encoded_stream(), m_entropy_coder_parallel); + } + return py::make_tuple(py::array_t(0), 1); +} + +at::Tensor DMCLDProxy::decompress(const py::array_t& bit_stream, const int qp, + const int height, const int width, + const int entropy_coder_parallel, const bool reset_feature_memory) +{ + m_result_ready = false; + m_entropy_coder_parallel = entropy_coder_parallel; + py::buffer_info bit_stream_buf = bit_stream.request(); + m_bit_stream = static_cast(bit_stream_buf.ptr); + m_bit_stream_size = static_cast(bit_stream.size()); + m_z_height = (height + 63) / 64; + m_z_width = (width + 63) / 64; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeZ; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_dec_0 ----------- + auto lambda_dec_0 = [&](const bool memory_has_value) { + apply_feature_adaptor(memory_has_value); + m_temporal_params = m_temporal_prior_encoder.forward(m_memory); + }; + + run(lambda_dec_0, m_gexec_dec_0, m_memory_has_value); + // ------------ end of lambda_dec_0 ------------ + + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (!m_result_ready) { + return at::Tensor(); + } + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_z_ready)); + + at::Tensor q_dec; + at::Tensor scales; + at::Tensor means; + // ----------- start of lambda_dec_1 ----------- + auto lambda_dec_1 = [&](const int qp) { + // need to output [m_y_indexes, m_y_size] for cpu thread + m_z_hat = int8_to_dtype_cuda(m_z_hat_io, m_dtype, g_ch_z, m_z_height, m_z_width, m_z_hat); + m_hyper_params_pad4 = m_hyper_decoder.forward(m_z_hat); + m_hyper_params = crop_hyper_params(m_hyper_params_pad4, m_temporal_params.size(2), + m_temporal_params.size(3), m_hyper_params); + m_temporal_params = multiply_with_broadcast_cuda(m_temporal_params, m_q_feature[qp], + m_temporal_params); // inplace + m_common_params = m_y_prior_fusion.forward(m_cat_prior_fusion); + std::tie(q_dec, scales, means) = chunk_tensors_3(m_common_params); + std::tie(m_y_indexes_prev, m_skip_cond) = build_index_dec_cuda( + scales, m_skip_threshold, at::nullopt, 0, m_y_indexes_prev, m_skip_cond); + std::tie(m_y_indexes, m_y_size, m_y_num) = + conditional_index_part1_cuda(m_y_indexes_prev, m_skip_cond, m_y_indexes, m_y_size, m_y_num); + }; + + run(lambda_dec_1, m_gexec_dec_1, m_qp); + // ------------ end of lambda_dec_1 ------------ + + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_dec_2 ----------- + auto lambda_dec_2 = [&]() { m_ctx = m_feature_extractor.forward(m_memory); }; + + run(lambda_dec_2, m_gexec_dec_2); + // ------------ end of lambda_dec_2 ------------ + + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (!m_result_ready) { + return at::Tensor(); + } + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_3 ----------- + auto lambda_dec_3 = [&](const int qp) { + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_skip_cond, m_y_num, + m_dtype, m_y_q_r); + m_y_hat = restore_y_cuda(m_y_q_r, means, m_mask_0, m_y_hat); + m_means = m_y_spatial_prior.forward(m_cat_spatial_prior); + m_y_hat = restore_y_and_add_multiply_inplace_cuda(m_y_q_r, m_means, m_mask_1, m_y_hat, q_dec); + // decoder + recon_head + m_feature_p = m_decoder.forward(m_y_hat, m_cat_decoder, m_q_decoder[qp]); + m_x_hat = m_recon_head.forward(m_feature_p); // m_feature_i is also updated for reset purpose + }; + + run(lambda_dec_3, m_gexec_dec_3, m_qp); + // ------------ end of lambda_dec_3 ------------ + + m_memory_has_value = !reset_feature_memory; // host operation. must be outside of cuda graph + + return m_x_hat; +} + +void DMCLDProxy::set_param(const std::map& state_dict, const float skip_threshold) +{ + m_device = state_dict.at("q_decoder").device(); + m_dtype = state_dict.at("q_decoder").scalar_type(); + auto q_encoder = state_dict.at("q_encoder"); + auto q_decoder = state_dict.at("q_decoder"); + auto q_feature = state_dict.at("q_feature"); + for (int i = 0; i < g_qp_num; i++) { + m_q_encoder[i] = q_encoder.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_decoder[i] = q_decoder.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_feature[i] = q_feature.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + } + m_encoder.set_param(get_submodule_state_dict(state_dict, "encoder.")); + m_hyper_encoder.set_param(get_submodule_state_dict(state_dict, "hyper_encoder.")); + m_temporal_prior_encoder.set_param( + get_submodule_state_dict(state_dict, "temporal_prior_encoder.")); + m_hyper_decoder.set_param(get_submodule_state_dict(state_dict, "hyper_decoder.")); + m_y_prior_fusion.set_param(get_submodule_state_dict(state_dict, "y_prior_fusion.")); + m_y_spatial_prior.set_param(get_submodule_state_dict(state_dict, "y_spatial_prior.")); + m_decoder.set_param(get_submodule_state_dict(state_dict, "decoder.")); + m_feature_adaptor_i.set_param(get_submodule_state_dict(state_dict, "feature_adaptor_i.")); + m_feature_adaptor_m.set_param(get_submodule_state_dict(state_dict, "feature_adaptor_m.")); + m_feature_extractor.set_param(get_submodule_state_dict(state_dict, "feature_extractor.")); + m_recon_head.set_param(get_submodule_state_dict(state_dict, "recon_head.")); + + m_skip_threshold = skip_threshold; + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); + + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); +} + +void DMCLDProxy::add_ref_feature_and_apply_adaptor(const at::Tensor& feature, + const bool reset_feature_memory) +{ + if (reset_feature_memory) { + auto out = m_recon_head.forward_reset(feature); + m_memory = m_feature_adaptor_i.forward(out); + } else { + m_memory = m_feature_adaptor_m.forward(m_cat_feature_adaptor_m); + } + m_ctx = m_feature_extractor.forward(m_memory); +} + +void DMCLDProxy::apply_feature_adaptor(const bool memory_has_value) +{ + if (memory_has_value) { + m_memory = m_feature_adaptor_m.forward(m_cat_feature_adaptor_m); + } else { + m_memory = m_feature_adaptor_i.forward(m_feature_i); + } +} + +void DMCLDProxy::clear_cuda_graph() +{ + for (int i = 0; i < g_qp_num; ++i) { + destroy_cuda_graph_exec(m_gexec_enc_0[i]); + for (int j = 0; j < 2; ++j) { + destroy_cuda_graph_exec(m_gexec_enc_1[i][j]); + } + } + for (int i = 0; i < 2; ++i) { + destroy_cuda_graph_exec(m_gexec_dec_0[i]); + } + destroy_cuda_graph_exec(m_gexec_dec_2); + for (int i = 0; i < g_qp_num; ++i) { + destroy_cuda_graph_exec(m_gexec_dec_1[i]); + destroy_cuda_graph_exec(m_gexec_dec_3[i]); + } +} + +std::tuple DMCLDProxy::get_mask_2x(const at::Tensor& y) +{ + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + auto m = at::ones({ 1, C / 2, H, W }, y.options().dtype(at::kBool)); + auto m0 = get_one_mask(torch::tensor({ { 1, 0 }, { 0, 1 } }, y.options().dtype(at::kBool)), H, W); + auto m1 = get_one_mask(torch::tensor({ { 0, 1 }, { 1, 0 } }, y.options().dtype(at::kBool)), H, W); + + auto mask_0 = at::cat({ m * m0, m * m1 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_1 = at::cat({ m * m1, m * m0 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + + return { mask_0, mask_1 }; +} + +void DMCLDProxy::pre_allocate_tensors(const at::Tensor& frame) +{ + int H = frame.size(2); + int W = frame.size(3); + H = (H + 16 - 1) / 16 * 16; + W = (W + 16 - 1) / 16 * 16; + const int H8 = H / 8; + const int W8 = W / 8; + if (m_H8 == H8 && m_W8 == W8) { + return; + } + + m_H8 = H8; + m_W8 = W8; + clear_cuda_graph(); + g_tensor_pool.clear(H8, W8); + + auto options = frame.options().memory_format(at::MemoryFormat::ChannelsLast); + const int H16 = H8 / 2; + const int W16 = W8 / 2; + auto [padR, padB] = get_padding_size(H16, W16, 4); + const int H16_pad4 = H16 + padB; + const int W16_pad4 = W16 + padR; + const int H64 = H16_pad4 / 4; + const int W64 = W16_pad4 / 4; + + const std::vector feature_i_shape = { 1, g_ch_src_d, H8, W8 }; + const std::vector y_shape = { 1, g_ch_y, H16, W16 }; + const std::vector y_pad_shape = { 1, g_ch_y, H16_pad4, W16_pad4 }; + const std::vector z_shape = { 1, g_ch_z, H64, W64 }; + + auto y = at::empty(y_shape, options); + + // pre allocate tensors + std::tie(m_mask_0, m_mask_1) = get_mask_2x(y); + m_y_decoded = at::empty({ y.numel() }, y.options().dtype(at::kChar)); + m_y_to_decode = std::make_shared>(y.numel()); + m_y_to_encode = std::make_shared>(y.numel()); + + // + // pre allocate concatenated tensors + // + + // 1. deal with m_cat_encoder, m_cat_decoder, m_enc_unshuffle_out, m_decoder_up_out, and m_ctx + assert(g_ch_d > g_ch_src_d); + at::Tensor tensor_placeholder; + m_cat_decoder = at::empty({ 1, g_ch_d + g_ch_m, H8, W8 }, options); + std::tie(tensor_placeholder, m_cat_encoder) = + split_tensors_2(m_cat_decoder, g_ch_d - g_ch_src_d, g_ch_src_d + g_ch_m); + std::tie(tensor_placeholder, m_enc_unshuffle_out, m_ctx) = + split_tensors_3(m_cat_decoder, g_ch_d - g_ch_src_d, g_ch_src_d, g_ch_m); + std::tie(m_decoder_up_out, m_ctx) = split_tensors_2(m_cat_decoder, g_ch_d, g_ch_m); + + // 2. deal with m_cat_feature_adaptor_m, m_memory, and m_feature_p + m_cat_feature_adaptor_m = at::empty({ 1, g_ch_m + g_ch_d, H8, W8 }, options); + std::tie(m_memory, m_feature_p) = split_tensors_2(m_cat_feature_adaptor_m, g_ch_m, g_ch_d); + + // 3. deal with m_cat_prior_fusion, m_hyper_params, and m_temporal_params + m_cat_prior_fusion = at::empty({ 1, g_ch_y * 3, H16, W16 }, options); + std::tie(m_hyper_params, m_temporal_params) = + split_tensors_2(m_cat_prior_fusion, g_ch_y, g_ch_y * 2); + m_hyper_params_pad4 = (padR == 0 && padB == 0) ? m_hyper_params : at::empty(y_pad_shape, options); + + // 4. deal with m_cat_spatial_prior, m_y_hat, and m_common_params + m_cat_spatial_prior = at::empty({ 1, g_ch_y * 4, H16, W16 }, options); + std::tie(m_y_hat, m_common_params) = split_tensors_2(m_cat_spatial_prior, g_ch_y, g_ch_y * 3); + + // pre allocate other tensors + m_feature_i = g_tensor_pool.empty(feature_i_shape, options); + + m_z_hat = at::empty(z_shape, options.dtype(at::kHalf)); + m_z_hat_io = at::empty(z_shape, options.dtype(at::kChar)); + + m_means = at::empty_like(y); + m_y_q = at::empty_like(y); + m_y_q_r = at::empty_like(y); + + m_y_symbol = at::empty({ y.numel() }, y.options().dtype(at::kShort)); + m_y_symbol_prev = at::empty_like(m_y_symbol); + m_y_indexes = at::empty({ y.numel() }, y.options().dtype(at::kByte)); + m_y_indexes_prev = at::empty_like(m_y_indexes); + m_skip_cond = at::empty({ y.numel() }, y.options().dtype(at::kBool)); + + const int block_num = (y.numel() + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + m_y_size = at::empty({ 1 }, y.options().dtype(at::kInt)); + m_y_num = at::empty({ block_num, COND_KERNEL_THREAD_NUM1 }, y.options().dtype(at::kInt)); + + // pre allocate modules + m_y = m_encoder.pre_allocate_tensors(m_cat_encoder); + m_y_pad = (padR == 0 && padB == 0) ? m_y : at::empty(y_pad_shape, options); + m_hyper_encoder.pre_allocate_tensors(m_y_pad); + m_temporal_prior_encoder.pre_allocate_tensors(m_memory, m_temporal_params); + m_hyper_decoder.pre_allocate_tensors(m_z_hat, m_hyper_params_pad4); + m_y_prior_fusion.pre_allocate_tensors(m_cat_prior_fusion, m_common_params); + m_y_spatial_prior.pre_allocate_tensors(m_cat_spatial_prior, m_means); + m_decoder.pre_allocate_tensors(m_y_hat, m_decoder_up_out, m_cat_decoder, m_feature_p); + m_feature_adaptor_i.pre_allocate_tensors(m_feature_i, m_memory); + m_feature_adaptor_m.pre_allocate_tensors(m_cat_feature_adaptor_m, m_memory); + m_feature_extractor.pre_allocate_tensors(m_memory, m_ctx); + m_x_hat = m_recon_head.pre_allocate_tensors(m_feature_p, m_feature_i); +} + +void DMCLDProxy::worker() +{ + at::cuda::CUDAStream high_priority_stream = at::cuda::getStreamFromPool(true); + at::cuda::CUDAStreamGuard guard(high_priority_stream); + + while (!m_finish) { + std::unique_lock lk(m_mutex_pending); + m_cv_pending.wait(lk, [this] { return m_pending || m_finish; }); + if (m_finish) { + break; + } + m_pending = false; + lk.unlock(); + + if (m_pending_work == DMCWorkType::Encode) { + m_entropy_encoder.reset(); + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + + auto out = conditional_index_part2_cuda(m_y_symbol, m_y_size, m_size_ptr); + CUDA_CHECK(cudaMemcpyAsync(m_y_to_encode->data(), out.data_ptr(), + (*m_size_ptr) * sizeof(int16_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaStreamSynchronize(at::cuda::getCurrentCUDAStream())); + m_entropy_coder_parallel = compute_ec_parallel(*m_size_ptr); + m_entropy_encoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + m_entropy_encoder.encode_y(m_y_to_encode, *m_size_ptr); + + auto t = tensor_to_vector_1d(m_z_hat_io); + m_entropy_encoder.encode_z(t, m_qp * g_ch_z, g_ch_z); + m_entropy_encoder.flush(); + } else if (m_pending_work == DMCWorkType::DecodeZ) { + m_entropy_decoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + m_entropy_decoder.set_stream(m_bit_stream, m_bit_stream_size); + const int z_num = g_ch_z * m_z_height * m_z_width; + m_entropy_decoder.decode_z(z_num, m_qp * g_ch_z, g_ch_z); + + auto z_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_z_hat_io.data_ptr(), z_cpu->data(), + z_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_z_ready, at::cuda::getCurrentCUDAStream())); + } else if (m_pending_work == DMCWorkType::DecodeY) { + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + auto out = conditional_index_part2_cuda(m_y_indexes, m_y_size, m_size_ptr); + const int y_num = *m_size_ptr; + CUDA_CHECK(cudaMemcpyAsync(m_y_to_decode->data(), out.data_ptr(), + y_num * sizeof(uint8_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + + m_entropy_decoder.decode_y(m_y_to_decode, y_num); + + auto y_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_y_decoded.data_ptr(), y_cpu->data(), + y_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_y_ready, at::cuda::getCurrentCUDAStream())); + } else { + assert(false); + } + + { + std::lock_guard lk_result(m_mutex_result); + m_result_ready = true; + } + m_cv_result.notify_one(); + } +} diff --git a/src/layers/extensions/inference/dmc_ld_proxy.h b/src/layers/extensions/inference/dmc_ld_proxy.h new file mode 100644 index 0000000..2ae1207 --- /dev/null +++ b/src/layers/extensions/inference/dmc_ld_proxy.h @@ -0,0 +1,330 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "dmc_common.h" + +class DMCLDDecoderProxy { +public: + DMCLDDecoderProxy() = default; + ~DMCLDDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& conv1_input, const at::Tensor& quant); + at::Tensor forward_part1(const at::Tensor& x); + at::Tensor forward_part2(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x, at::Tensor& up_out_buf, + at::Tensor& conv1_input_buf, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + SubpelConv2xProxy m_up; + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv12; + at::Tensor m_conv2_weight; + at::Tensor m_conv2_bias; + + // for cuda graphs + at::Tensor m_conv2_out; +}; + +class DMCLDEncoderProxy { +public: + DMCLDEncoderProxy() = default; + ~DMCLDEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv2; + at::Tensor m_down_weight; + at::Tensor m_down_bias; + + // for cuda graph + at::Tensor m_down_out; +}; + +class DMCLDFeatureAdaptorIProxy { +public: + DMCLDFeatureAdaptorIProxy() = default; + ~DMCLDFeatureAdaptorIProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; +}; + +class DMCLDFeatureAdaptorMProxy { +public: + DMCLDFeatureAdaptorMProxy() = default; + ~DMCLDFeatureAdaptorMProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; +}; + +class DMCLDFeatureExtractorProxy { +public: + DMCLDFeatureExtractorProxy() = default; + ~DMCLDFeatureExtractorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; + DepthConvBlockProxy m_conv4; +}; + +class DMCLDHyperDecoderProxy { +public: + DMCLDHyperDecoderProxy() = default; + ~DMCLDHyperDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockUpsampleProxy m_conv0; + ResidualBlockUpsampleProxy m_conv1; + DepthConvBlockProxy m_conv2; +}; + +class DMCLDHyperEncoderProxy { +public: + DMCLDHyperEncoderProxy() = default; + ~DMCLDHyperEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + ResidualBlockWithStride2Proxy m_conv1; + ResidualBlockWithStride2Proxy m_conv2; +}; + +class DMCLDPriorFusionProxy { +public: + DMCLDPriorFusionProxy() = default; + ~DMCLDPriorFusionProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graphs + at::Tensor m_conv3_out; +}; + +class DMCLDReconHeadProxy { +public: + DMCLDReconHeadProxy() = default; + ~DMCLDReconHeadProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor forward_reset(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_head_weight; + at::Tensor m_head_bias; + + // for cuda graphs + at::Tensor m_head_out; + at::Tensor m_shuffle_out; +}; + +class DMCLDSpatialPriorProxy { +public: + DMCLDSpatialPriorProxy() = default; + ~DMCLDSpatialPriorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + at::Tensor m_conv2_weight; + at::Tensor m_conv2_bias; + + // for cuda graphs + at::Tensor m_conv2_out; +}; + +class DMCLDTemporalPriorEncoderProxy { +public: + DMCLDTemporalPriorEncoderProxy() = default; + ~DMCLDTemporalPriorEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockWithStride2Proxy m_conv; +}; + +class DMCLDProxy : public DMCCommon { +public: + static constexpr int g_ch_src_d = 3 * 8 * 8; + static constexpr int g_ch_y = 128; + static constexpr int g_ch_z = 128; + static constexpr int g_ch_d = 256; + static constexpr int g_ch_m = 256; + + DMCLDProxy(); + ~DMCLDProxy(); + + void add_ref_feature_from_frame(const at::Tensor& frame, const bool apply_adaptor); + py::tuple compress(const at::Tensor& x, const int qp, const bool reset_feature_memory, + const int padding_b, const int padding_r); + at::Tensor decompress(const py::array_t& bit_stream, const int qp, const int height, + const int width, const int entropy_coder_parallel, + const bool reset_feature_memory); + void set_param(const std::map& state_dict, const float skip_threshold); + +private: + // compress and decompress components + void add_ref_feature_and_apply_adaptor(const at::Tensor& feature, const bool reset_feature_memory); + void apply_feature_adaptor(const bool memory_none); + + // cuda graph related + void clear_cuda_graph(); + + // helper functions + std::tuple get_mask_2x(const at::Tensor& y); + + void pre_allocate_tensors(const at::Tensor& frame); + void worker(); + +private: + at::Tensor m_q_encoder[g_qp_num]; + at::Tensor m_q_decoder[g_qp_num]; + at::Tensor m_q_feature[g_qp_num]; + + DMCLDEncoderProxy m_encoder; + DMCLDHyperEncoderProxy m_hyper_encoder; + DMCLDTemporalPriorEncoderProxy m_temporal_prior_encoder; + DMCLDHyperDecoderProxy m_hyper_decoder; + DMCLDPriorFusionProxy m_y_prior_fusion; + DMCLDSpatialPriorProxy m_y_spatial_prior; + DMCLDDecoderProxy m_decoder; + DMCLDFeatureAdaptorIProxy m_feature_adaptor_i; + DMCLDFeatureAdaptorMProxy m_feature_adaptor_m; + DMCLDFeatureExtractorProxy m_feature_extractor; + DMCLDReconHeadProxy m_recon_head; + + float m_skip_threshold{ 0.f }; + + bool m_finish{ false }; + bool m_result_ready{ false }; + std::thread m_thread; + std::mutex m_mutex_result; + std::mutex m_mutex_pending; + std::condition_variable m_cv_pending; + std::condition_variable m_cv_result; + bool m_pending{ false }; + DMCWorkType m_pending_work; + + uint8_t* m_bit_stream{ nullptr }; + int m_bit_stream_size{ 0 }; + int m_z_width{ 0 }; + int m_z_height{ 0 }; + + cudaEvent_t m_event_y; + cudaEvent_t m_event_z_ready; + cudaEvent_t m_event_y_ready; + int* m_size_ptr{ nullptr }; + + int m_qp{ 0 }; + std::shared_ptr> m_y_to_encode{ nullptr }; + std::shared_ptr> m_y_to_decode{ nullptr }; + + at::ScalarType m_dtype; + at::Device m_device{ at::kCUDA }; + + // for cuda graph + int m_H8{ 0 }; + int m_W8{ 0 }; + cudaGraphExec_t m_gexec_enc_0[g_qp_num]{ nullptr }; + cudaGraphExec_t m_gexec_enc_1[g_qp_num][2]{ nullptr }; + cudaGraphExec_t m_gexec_dec_0[2]{ nullptr }; + cudaGraphExec_t m_gexec_dec_1[g_qp_num]{ nullptr }; + cudaGraphExec_t m_gexec_dec_2{ nullptr }; + cudaGraphExec_t m_gexec_dec_3[g_qp_num]{ nullptr }; + bool m_memory_has_value{ true }; + at::Tensor m_mask_0; + at::Tensor m_mask_1; + at::Tensor m_enc_unshuffle_out; + at::Tensor m_feature_i; // output of both image frame unshuffle and recon_head reset + at::Tensor m_feature_p; // output of decoder + at::Tensor m_memory; // output of both feature_adaptor_i and feature_adaptor_m + at::Tensor m_ctx; + at::Tensor m_temporal_params; + at::Tensor m_y; + at::Tensor m_y_pad; + at::Tensor m_hyper_params; + at::Tensor m_hyper_params_pad4; + at::Tensor m_z_hat; + at::Tensor m_z_hat_io; + at::Tensor m_common_params; + at::Tensor m_means; + at::Tensor m_y_q; + at::Tensor m_y_q_r; // only for decompress + at::Tensor m_y_hat; + at::Tensor m_y_symbol; + at::Tensor m_y_symbol_prev; + at::Tensor m_y_indexes; + at::Tensor m_y_indexes_prev; + at::Tensor m_skip_cond; + at::Tensor m_y_decoded; + at::Tensor m_y_size; + at::Tensor m_y_num; + at::Tensor m_decoder_up_out; + at::Tensor m_x_hat; // no allocation + + // 5 concatenated tensors + at::Tensor m_cat_encoder; + at::Tensor m_cat_decoder; + at::Tensor m_cat_feature_adaptor_m; + at::Tensor m_cat_prior_fusion; + at::Tensor m_cat_spatial_prior; +}; diff --git a/src/layers/extensions/inference/dmci_proxy.cpp b/src/layers/extensions/inference/dmci_proxy.cpp new file mode 100644 index 0000000..416e776 --- /dev/null +++ b/src/layers/extensions/inference/dmci_proxy.cpp @@ -0,0 +1,882 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include +#include + +#include "common_cpp.h" +#include "cuda_check.h" +#include "def_cutlass.h" +#include "def_elementwise.h" +#include "dmci_proxy.h" +#include "memory_pool.h" + +at::Tensor DMCIDecoderProxy::forward(const at::Tensor& x, const at::Tensor& quant) +{ + auto out = m_up.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = m_conv3.forward(out); + out = m_conv4.forward(out); + out = m_conv5.forward(out); + out = m_conv6.forward(out); + out = m_conv7.forward(out); + out = m_conv8.forward(out); + out = m_conv9.forward(out); + out = m_conv10.forward(out); + out = m_conv11.forward(out); + out = m_conv12.forward(out); + out = multiply_with_broadcast_cuda(out, quant, out); + out = m_dec_2.forward(out); + out = pixel_shuffle_8_cuda(out, true, m_shuffle_out); + return out; +} + +at::Tensor DMCIDecoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = x.options().memory_format(at::MemoryFormat::ChannelsLast); + // dec_2 output channels = g_ch_src = 192, pixel_shuffle_8 → 192/64 = 3 + m_shuffle_out = at::empty({ 1, 3, H * 2 * 8, W * 2 * 8 }, options); + auto out = m_up.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + out = m_conv3.pre_allocate_tensors(out); + out = m_conv4.pre_allocate_tensors(out); + out = m_conv5.pre_allocate_tensors(out); + out = m_conv6.pre_allocate_tensors(out); + out = m_conv7.pre_allocate_tensors(out); + out = m_conv8.pre_allocate_tensors(out); + out = m_conv9.pre_allocate_tensors(out); + out = m_conv10.pre_allocate_tensors(out); + out = m_conv11.pre_allocate_tensors(out); + out = m_conv12.pre_allocate_tensors(out); + out = m_dec_2.pre_allocate_tensors(out); + + m_up.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + m_conv3.release_tensors(); + m_conv4.release_tensors(); + m_conv5.release_tensors(); + m_conv6.release_tensors(); + m_conv7.release_tensors(); + m_conv8.release_tensors(); + m_conv9.release_tensors(); + m_conv10.release_tensors(); + m_conv11.release_tensors(); + m_conv12.release_tensors(); + m_dec_2.release_tensors(); + return m_shuffle_out; +} + +void DMCIDecoderProxy::set_param(const std::map& state_dict) +{ + m_up.set_param(get_submodule_state_dict(state_dict, "dec_1.0."), true); + m_conv1.set_param(get_submodule_state_dict(state_dict, "dec_1.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "dec_1.2.")); + m_conv3.set_param(get_submodule_state_dict(state_dict, "dec_1.3.")); + m_conv4.set_param(get_submodule_state_dict(state_dict, "dec_1.4.")); + m_conv5.set_param(get_submodule_state_dict(state_dict, "dec_1.5.")); + m_conv6.set_param(get_submodule_state_dict(state_dict, "dec_1.6.")); + m_conv7.set_param(get_submodule_state_dict(state_dict, "dec_1.7.")); + m_conv8.set_param(get_submodule_state_dict(state_dict, "dec_1.8.")); + m_conv9.set_param(get_submodule_state_dict(state_dict, "dec_1.9.")); + m_conv10.set_param(get_submodule_state_dict(state_dict, "dec_1.10.")); + m_conv11.set_param(get_submodule_state_dict(state_dict, "dec_1.11.")); + m_conv12.set_param(get_submodule_state_dict(state_dict, "dec_1.12.")); + m_dec_2.set_param(get_submodule_state_dict(state_dict, "dec_2.")); +} + +at::Tensor DMCIEncoderProxy::forward(const at::Tensor& x, const at::Tensor& quant) +{ + const int sm = get_gpu_sm(); + auto out = m_enc_1.forward(x); + out = multiply_with_broadcast_cuda(out, quant, out); + out = m_enc_2_0.forward(out); + out = m_enc_2_1.forward(out); + out = m_enc_2_2.forward(out); + out = m_enc_2_3.forward(out); + out = m_enc_2_4.forward(out); + out = m_enc_2_5.forward(out); + out = conv_bias(sm, out, m_down_weight, m_down_bias, 2, m_down_out); + return out; +} + +at::Tensor DMCIEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_down_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_down = m_down_weight.size(0); + m_down_out = g_tensor_pool.empty({ 1, ch_down, H / 2, W / 2 }, options); + auto out = m_enc_1.pre_allocate_tensors(x, true); + out = m_enc_2_0.pre_allocate_tensors(out); + out = m_enc_2_1.pre_allocate_tensors(out); + out = m_enc_2_2.pre_allocate_tensors(out); + out = m_enc_2_3.pre_allocate_tensors(out); + out = m_enc_2_4.pre_allocate_tensors(out); + out = m_enc_2_5.pre_allocate_tensors(out); + + m_enc_1.release_tensors(); + m_enc_2_0.release_tensors(); + m_enc_2_1.release_tensors(); + m_enc_2_2.release_tensors(); + m_enc_2_3.release_tensors(); + m_enc_2_4.release_tensors(); + m_enc_2_5.release_tensors(); + return m_down_out; +} + +void DMCIEncoderProxy::set_param(const std::map& state_dict) +{ + m_enc_1.set_param(get_submodule_state_dict(state_dict, "enc_1.")); + m_enc_2_0.set_param(get_submodule_state_dict(state_dict, "enc_2.0.")); + m_enc_2_1.set_param(get_submodule_state_dict(state_dict, "enc_2.1.")); + m_enc_2_2.set_param(get_submodule_state_dict(state_dict, "enc_2.2.")); + m_enc_2_3.set_param(get_submodule_state_dict(state_dict, "enc_2.3.")); + m_enc_2_4.set_param(get_submodule_state_dict(state_dict, "enc_2.4.")); + m_enc_2_5.set_param(get_submodule_state_dict(state_dict, "enc_2.5.")); + m_down_weight = state_dict.at("enc_2.6.weight"); + m_down_bias = state_dict.at("enc_2.6.bias"); +} + +at::Tensor DMCIHyperDecoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCIHyperDecoderProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + auto out = m_conv0.pre_allocate_tensors(x); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out, false, out_buf); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCIHyperDecoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0."), true); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), true); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); +} + +at::Tensor DMCIHyperEncoderProxy::forward(const at::Tensor& x) +{ + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + return out; +} + +at::Tensor DMCIHyperEncoderProxy::pre_allocate_tensors(at::Tensor& x) +{ + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + g_tensor_pool.set_reusable(out, false); + return out; +} + +void DMCIHyperEncoderProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1."), true); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2."), true); +} + +at::Tensor DMCISpatialPriorProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCISpatialPriorProxy::pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf) +{ + m_conv3_out = out_buf; + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCISpatialPriorProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +at::Tensor DMCIYPriorFusionProxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = m_conv0.forward(x); + out = m_conv1.forward(out); + out = m_conv2.forward(out); + out = conv1x1_bias(sm, out, m_conv3_weight, m_conv3_bias, m_conv3_out); + return out; +} + +at::Tensor DMCIYPriorFusionProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_conv3_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_conv3 = m_conv3_weight.size(0); + m_conv3_out = g_tensor_pool.empty({ 1, ch_conv3, H, W }, options); + auto out = m_conv0.pre_allocate_tensors(x, true); + out = m_conv1.pre_allocate_tensors(out); + out = m_conv2.pre_allocate_tensors(out); + + m_conv0.release_tensors(); + m_conv1.release_tensors(); + m_conv2.release_tensors(); + return m_conv3_out; +} + +void DMCIYPriorFusionProxy::set_param(const std::map& state_dict) +{ + m_conv0.set_param(get_submodule_state_dict(state_dict, "conv.0.")); + m_conv1.set_param(get_submodule_state_dict(state_dict, "conv.1.")); + m_conv2.set_param(get_submodule_state_dict(state_dict, "conv.2.")); + m_conv3_weight = state_dict.at("conv.3.weight"); + m_conv3_bias = state_dict.at("conv.3.bias"); +} + +DMCIProxy::DMCIProxy() +{ + CUDA_CHECK(cudaMallocHost((void**)&m_size_ptr, sizeof(int))); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_z_ready, cudaEventDisableTiming)); + CUDA_CHECK(cudaEventCreateWithFlags(&m_event_y_ready, cudaEventDisableTiming)); + m_thread = std::thread(&DMCIProxy::worker, this); +} + +DMCIProxy::~DMCIProxy() +{ + { + std::lock_guard lk(m_mutex_pending); + m_finish = true; + } + m_cv_pending.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } + cudaEventDestroy(m_event_y); + cudaEventDestroy(m_event_z_ready); + cudaEventDestroy(m_event_y_ready); + cudaFreeHost(m_size_ptr); + + clear_cuda_graph(); +} + +py::tuple DMCIProxy::compress(const at::Tensor& x, const int qp, const int padding_b, const int padding_r) +{ + pre_allocate_tensors(x.size(2), x.size(3)); + m_result_ready = false; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + // must NOT use cuda graph because x.data_ptr() is non-const + m_enc_unshuffle_out = pad_and_unshuffle_8_cuda(x, padding_b, padding_r, m_enc_unshuffle_out); + + // ----------- start of lambda_enc_0 ----------- + auto lambda_enc_0 = [&](const int qp) { + // encoder → y + auto y = m_encoder.forward(m_enc_unshuffle_out, m_q_scale_enc[qp]); + auto y_pad = pad_for_y(y, m_y_pad); + // hyper encoder → z → z_hat + auto z = m_hyper_encoder.forward(y_pad); + std::tie(m_z_hat, m_z_hat_io) = round_z_cuda(z, m_z_hat, m_z_hat_io); + // hyper decoder → prior fusion → crop → common_params + m_hyper_params = m_hyper_decoder.forward(m_z_hat); + auto params = m_y_prior_fusion.forward(m_hyper_params); + const int yH = y.size(2); + const int yW = y.size(3); + params = crop_hyper_params(params, yH, yW, m_cropped_params); + + // separate prior: scales, means are views of common_params + auto [scales, means] = chunk_tensors_2(params); + + // y_enc = y * q_scale_y_enc (inplace) + y = multiply_with_broadcast_cuda(y, m_q_scale_y_enc[qp], y); + + // reduction for spatial prior + const int sm = get_gpu_sm(); + m_reduced_params = conv1x1_bias(sm, params, m_y_spatial_prior_reduction.weight, + m_y_spatial_prior_reduction.bias, m_reduced_params); + + // Step 0: process with mask_0 + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_0, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[0], m_y_size[0], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[0], m_y_size[0], m_y_num); + + // copy y_hat to y_hat_so_far (first 256 channels of m_cat_spatial_prior_adaptor) + m_y_hat_so_far.copy_(m_y_hat); + + // Step 1: adaptor_1 → spatial_prior → new scales, means + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_1.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_1, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[1], m_y_size[1], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[1], m_y_size[1], m_y_num); + + // y_hat_so_far += y_hat_1 + m_y_hat_so_far.add_(m_y_hat); + + // Step 2: adaptor_2 → spatial_prior → new scales, means + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_2.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_2, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[2], m_y_size[2], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[2], m_y_size[2], m_y_num); + + // y_hat_so_far += y_hat_2 + m_y_hat_so_far.add_(m_y_hat); + + // Step 3: adaptor_3 → spatial_prior → new scales, means + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_3.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + std::tie(m_y_q, m_y_hat, m_s_hat) = process_with_mask_cuda( + y, scales, means, m_mask_3, m_skip_threshold, 0, m_y_q, m_y_hat, m_s_hat); + m_y_q_w = single_part_for_writing_4x_cuda(m_y_q, m_y_q_w); + m_s_w = single_part_for_writing_4x_cuda(m_s_hat, m_s_w); + std::tie(m_y_symbol_prev, m_skip_cond) = build_index_enc_cuda( + m_y_q_w, m_s_w, m_skip_threshold, at::nullopt, 0, m_y_symbol_prev, m_skip_cond); + std::tie(m_y_symbol[3], m_y_size[3], m_y_num) = conditional_index_part1_cuda( + m_y_symbol_prev, m_skip_cond, m_y_symbol[3], m_y_size[3], m_y_num); + + // y_hat_final = (y_hat_so_far + y_hat_3) * q_scale_y_dec + m_y_hat = + add_and_multiply_broadcast_cuda(m_y_hat_so_far, m_y_hat, m_q_scale_y_dec[qp], m_y_hat); + }; + + run(lambda_enc_0, m_gexec_enc_0, m_qp); + // ------------ end of lambda_enc_0 ------------ + + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::Encode; + } + m_cv_pending.notify_one(); + + // ----------- start of lambda_enc_1 ----------- + auto lambda_enc_1 = [&](const int qp) { + m_x_hat = m_decoder.forward(m_y_hat, m_q_scale_dec[qp]); + }; + + run(lambda_enc_1, m_gexec_enc_1, m_qp); + // ------------ end of lambda_enc_1 ------------ + + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (m_result_ready) { + return py::make_tuple(m_entropy_encoder.get_encoded_stream(), m_x_hat, m_entropy_coder_parallel); + } + return py::make_tuple(py::array_t(0), at::Tensor(), 1); +} + +at::Tensor DMCIProxy::decompress(const py::array_t& bit_stream, const int qp, + const int height, const int width, const int entropy_coder_parallel) +{ + pre_allocate_tensors(height, width); + m_result_ready = false; + m_entropy_coder_parallel = entropy_coder_parallel; + py::buffer_info bit_stream_buf = bit_stream.request(); + m_bit_stream = static_cast(bit_stream_buf.ptr); + m_bit_stream_size = static_cast(bit_stream.size()); + m_z_height = (height + 63) / 64; + m_z_width = (width + 63) / 64; + m_qp = qp; + + auto stream = at::cuda::getCurrentCUDAStream(); + + // Signal worker to decode Z + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeZ; + } + m_cv_pending.notify_one(); + + // Wait for Z decode + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + if (!m_result_ready) { + return at::Tensor(); + } + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_z_ready)); + + at::Tensor scales; + at::Tensor means; + + // ----------- start of lambda_dec_0 ----------- + auto lambda_dec_0 = [&]() { + // int8_to_fp16 → hyper_dec → prior_fusion → crop → chunk2 → reduction + m_z_hat = int8_to_dtype_cuda(m_z_hat_io, m_dtype, g_ch_z, m_z_height, m_z_width, m_z_hat); + m_hyper_params = m_hyper_decoder.forward(m_z_hat); + auto params = m_y_prior_fusion.forward(m_hyper_params); + const int yH = (height + 15) / 16; + const int yW = (width + 15) / 16; + params = crop_hyper_params(params, yH, yW, m_cropped_params); + std::tie(scales, means) = chunk_tensors_2(params); + const int sm = get_gpu_sm(); + m_reduced_params = conv1x1_bias(sm, params, m_y_spatial_prior_reduction.weight, + m_y_spatial_prior_reduction.bias, m_reduced_params); + // Step 0: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_0, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_0, m_gexec_dec_0); + // ------------ end of lambda_dec_0 ------------ + + // Step 0: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_1 ----------- + auto lambda_dec_1 = [&]() { + // Step 0: recover + restore + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + m_y_hat_so_far = restore_y_4x_cuda(m_y_q_r, means, m_mask_0, m_y_hat_so_far); + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_1.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + // Step 1: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_1, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_1, m_gexec_dec_1); + // ------------ end of lambda_dec_1 ------------ + + // Step 1: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_2 ----------- + auto lambda_dec_2 = [&]() { + // Step 1: recover + restore + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + restore_y_4x_and_add_inplace_cuda(m_y_q_r, means, m_mask_1, m_y_hat_so_far); + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_2.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + // Step 2: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_2, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_2, m_gexec_dec_2); + // ------------ end of lambda_dec_2 ------------ + + // Step 2: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_3 ----------- + auto lambda_dec_3 = [&]() { + // Step 2: recover + restore + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + restore_y_4x_and_add_inplace_cuda(m_y_q_r, means, m_mask_2, m_y_hat_so_far); + m_spatial_prior_out = m_y_spatial_prior.forward( + m_y_spatial_prior_adaptor_3.forward(m_cat_spatial_prior_adaptor)); + std::tie(scales, means) = chunk_tensors_2(m_spatial_prior_out); + // Step 3: build index + m_y_indexes = + decode_y_step_build_index(scales, m_mask_3, m_y_indexes_skip_cond, m_y_indexes_num); + }; + run(lambda_dec_3, m_gexec_dec_3); + // ------------ end of lambda_dec_3 ------------ + + // Step 3: entropy (worker thread) + CUDA_CHECK(cudaEventRecord(m_event_y, stream)); + { + std::unique_lock lk(m_mutex_pending); + m_pending = true; + m_pending_work = DMCWorkType::DecodeY; + } + m_cv_pending.notify_one(); + { + std::unique_lock lk(m_mutex_result); + m_cv_result.wait(lk, [this] { return m_result_ready || m_finish; }); + m_result_ready = false; + } + CUDA_CHECK(cudaStreamWaitEvent(stream, m_event_y_ready)); + + // ----------- start of lambda_dec_4 ----------- + auto lambda_dec_4 = [&](const int qp) { + // Step 3: recover + restore (QP-dependent due to q_scale_y_dec) + m_y_q_r = conditional_recover_with_type_conversion_cuda(m_y_decoded, m_y_indexes_skip_cond, + m_y_indexes_num, m_dtype, m_y_q_r); + m_y_hat = restore_y_4x_add_and_multiply_broadcast_cuda( + m_y_q_r, means, m_mask_3, m_y_hat_so_far, m_q_scale_y_dec[qp], m_y_hat); + // decoder + m_x_hat = m_decoder.forward(m_y_hat, m_q_scale_dec[qp]); + }; + run(lambda_dec_4, m_gexec_dec_4, m_qp); + // ------------ end of lambda_dec_4 ------------ + + return m_x_hat; +} + +void DMCIProxy::set_param(const std::map& state_dict, const float skip_threshold) +{ + m_device = state_dict.at("q_scale_dec").device(); + m_dtype = state_dict.at("q_scale_dec").scalar_type(); + auto q_scale_enc = state_dict.at("q_scale_enc"); + auto q_scale_dec = state_dict.at("q_scale_dec"); + auto q_scale_y_enc = state_dict.at("q_scale_y_enc"); + auto q_scale_y_dec = state_dict.at("q_scale_y_dec"); + for (int i = 0; i < g_qp_num; i++) { + m_q_scale_enc[i] = q_scale_enc.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_scale_dec[i] = q_scale_dec.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_scale_y_enc[i] = + q_scale_y_enc.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + m_q_scale_y_dec[i] = + q_scale_y_dec.index({ at::indexing::Slice(i, i + 1), at::indexing::Slice(), + at::indexing::None, at::indexing::None }); + } + m_encoder.set_param(get_submodule_state_dict(state_dict, "enc.")); + m_hyper_encoder.set_param(get_submodule_state_dict(state_dict, "hyper_enc.")); + m_hyper_decoder.set_param(get_submodule_state_dict(state_dict, "hyper_dec.")); + m_y_prior_fusion.set_param(get_submodule_state_dict(state_dict, "y_prior_fusion.")); + m_y_spatial_prior_reduction.set_param(state_dict, "y_spatial_prior_reduction."); + m_y_spatial_prior_adaptor_1.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_1.")); + m_y_spatial_prior_adaptor_2.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_2.")); + m_y_spatial_prior_adaptor_3.set_param( + get_submodule_state_dict(state_dict, "y_spatial_prior_adaptor_3.")); + m_y_spatial_prior.set_param(get_submodule_state_dict(state_dict, "y_spatial_prior.")); + m_decoder.set_param(get_submodule_state_dict(state_dict, "dec.")); + + m_skip_threshold = skip_threshold; + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_encoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); + + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("bit_estimator_z.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("bit_estimator_z.cdf_length")), 0); + m_entropy_decoder.set_cdf( + tensor_to_vector_1d(state_dict.at("gaussian_encoder.quantized_cdf")), + tensor_to_vector_1d(state_dict.at("gaussian_encoder.cdf_length")), 1); +} + +void DMCIProxy::clear_cuda_graph() +{ + for (int i = 0; i < g_qp_num; ++i) { + destroy_cuda_graph_exec(m_gexec_enc_0[i]); + destroy_cuda_graph_exec(m_gexec_enc_1[i]); + destroy_cuda_graph_exec(m_gexec_dec_4[i]); + } + destroy_cuda_graph_exec(m_gexec_dec_0); + destroy_cuda_graph_exec(m_gexec_dec_1); + destroy_cuda_graph_exec(m_gexec_dec_2); + destroy_cuda_graph_exec(m_gexec_dec_3); +} + +at::Tensor DMCIProxy::decode_y_step_build_index(const at::Tensor& scales, const at::Tensor& mask, + at::Tensor& skip_cond_out, at::Tensor& indexes_num_out) +{ + m_scales_r = single_part_for_reading_4x_cuda(scales, mask, m_scales_r); + std::tie(m_y_indexes_prev, skip_cond_out) = build_index_dec_cuda( + m_scales_r, m_skip_threshold, at::nullopt, 0, m_y_indexes_prev, skip_cond_out); + std::tie(m_y_indexes, m_y_indexes_size, indexes_num_out) = conditional_index_part1_cuda( + m_y_indexes_prev, skip_cond_out, m_y_indexes, m_y_indexes_size, indexes_num_out); + return m_y_indexes; +} + +std::tuple DMCIProxy::get_mask_4x(const at::Tensor& y) +{ + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + auto m = at::ones({ 1, C / 4, H, W }, y.options().dtype(at::kBool)); + auto m0 = get_one_mask(torch::tensor({ { 1, 0 }, { 0, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m1 = get_one_mask(torch::tensor({ { 0, 1 }, { 0, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m2 = get_one_mask(torch::tensor({ { 0, 0 }, { 1, 0 } }, y.options().dtype(at::kBool)), H, W); + auto m3 = get_one_mask(torch::tensor({ { 0, 0 }, { 0, 1 } }, y.options().dtype(at::kBool)), H, W); + + auto mask_0 = + at::cat({ m * m0, m * m1, m * m2, m * m3 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_1 = + at::cat({ m * m3, m * m2, m * m1, m * m0 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_2 = + at::cat({ m * m2, m * m3, m * m0, m * m1 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + auto mask_3 = + at::cat({ m * m1, m * m0, m * m3, m * m2 }, 1).contiguous(at::MemoryFormat::ChannelsLast); + + return { mask_0, mask_1, mask_2, mask_3 }; +} + +void DMCIProxy::pre_allocate_tensors(const int height, const int width) +{ + int H = height; + int W = width; + H = (H + 16 - 1) / 16 * 16; + W = (W + 16 - 1) / 16 * 16; + const int H8 = H / 8; + const int W8 = W / 8; + if (m_H8 == H8 && m_W8 == W8) { + return; + } + + m_H8 = H8; + m_W8 = W8; + clear_cuda_graph(); + g_tensor_pool.clear(H8, W8); + + auto options = at::TensorOptions().device(m_device).dtype(m_dtype).memory_format( + at::MemoryFormat::ChannelsLast); + const int H16 = H8 / 2; + const int W16 = W8 / 2; + auto [padR, padB] = get_padding_size(H16, W16, 4); + const int H16_pad4 = H16 + padB; + const int W16_pad4 = W16 + padR; + const int H64 = H16_pad4 / 4; + const int W64 = W16_pad4 / 4; + + const std::vector y_shape = { 1, g_ch_y, H16, W16 }; + const std::vector y_pad_shape = { 1, g_ch_y, H16_pad4, W16_pad4 }; + const std::vector z_shape = { 1, g_ch_z, H64, W64 }; + + auto y = at::empty(y_shape, options); + + // pre allocate masks + std::tie(m_mask_0, m_mask_1, m_mask_2, m_mask_3) = get_mask_4x(y); + const int y_quarter_numel = y.numel() / 4; + m_y_decoded = at::empty({ y_quarter_numel }, y.options().dtype(at::kChar)); + m_y_to_decode = std::make_shared>(y_quarter_numel); + for (int i = 0; i < 4; i++) { + m_y_to_encode[i] = std::make_shared>(y_quarter_numel); + } + + // pre allocate concatenated tensor for spatial prior adaptor + m_cat_spatial_prior_adaptor = at::empty({ 1, g_ch_y * 2, H16, W16 }, options); + std::tie(m_y_hat_so_far, m_reduced_params) = + split_tensors_2(m_cat_spatial_prior_adaptor, g_ch_y, g_ch_y); + + // pre allocate other tensors + m_enc_unshuffle_out = at::empty({ 1, g_ch_src, H8, W8 }, options); + m_z_hat = at::empty(z_shape, options.dtype(at::kHalf)); + m_z_hat_io = at::empty(z_shape, options.dtype(at::kChar)); + m_hyper_params = at::empty({ 1, g_ch_y, H16_pad4, W16_pad4 }, options); + m_cropped_params = at::empty({ 1, g_ch_y * 2, H16, W16 }, options); + m_y_q = at::empty_like(y); + m_y_hat = at::empty_like(y); + m_s_hat = at::empty_like(y); + m_y_q_r = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_scales_r = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_spatial_prior_out = at::empty({ 1, g_ch_y * 2, H16, W16 }, options); + + m_y_q_w = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_s_w = at::empty({ 1, g_ch_y / 4, H16, W16 }, options); + m_y_symbol_prev = at::empty({ y_quarter_numel }, y.options().dtype(at::kShort)); + m_skip_cond = at::empty({ y_quarter_numel }, y.options().dtype(at::kBool)); + { + const int block_num = + (y_quarter_numel + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + m_y_num = at::empty({ block_num, COND_KERNEL_THREAD_NUM1 }, y.options().dtype(at::kInt)); + } + for (int i = 0; i < 4; i++) { + m_y_symbol[i] = at::empty({ y_quarter_numel }, y.options().dtype(at::kShort)); + m_y_size[i] = at::empty({ 1 }, y.options().dtype(at::kInt)); + } + + // decompress-only buffers + m_y_indexes = at::empty({ y_quarter_numel }, y.options().dtype(at::kByte)); + m_y_indexes_prev = at::empty_like(m_y_indexes); + m_y_indexes_skip_cond = at::empty({ y_quarter_numel }, y.options().dtype(at::kBool)); + { + const int block_num = + (y_quarter_numel + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + m_y_indexes_size = at::empty({ 1 }, y.options().dtype(at::kInt)); + m_y_indexes_num = + at::empty({ block_num, COND_KERNEL_THREAD_NUM1 }, y.options().dtype(at::kInt)); + } + + // pre allocate sub-module tensors + m_y = m_encoder.pre_allocate_tensors(m_enc_unshuffle_out); + m_y_pad = (padR == 0 && padB == 0) ? m_y : at::empty(y_pad_shape, options); + m_hyper_encoder.pre_allocate_tensors(m_y_pad); + m_hyper_decoder.pre_allocate_tensors(m_z_hat, m_hyper_params); + m_y_prior_fusion.pre_allocate_tensors(m_hyper_params); + // m_cropped_params stays at unpadded size [1, 512, H16, W16] for crop_hyper_params output + auto adaptor_out = + m_y_spatial_prior_adaptor_1.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true); + m_y_spatial_prior_adaptor_2.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true, adaptor_out); + m_y_spatial_prior_adaptor_3.pre_allocate_tensors(m_cat_spatial_prior_adaptor, true, adaptor_out); + m_y_spatial_prior.pre_allocate_tensors(adaptor_out, m_spatial_prior_out); + m_x_hat = m_decoder.pre_allocate_tensors(m_y_hat); +} + +void DMCIProxy::worker() +{ + at::cuda::CUDAStream high_priority_stream = at::cuda::getStreamFromPool(true); + at::cuda::CUDAStreamGuard guard(high_priority_stream); + + while (!m_finish) { + std::unique_lock lk(m_mutex_pending); + m_cv_pending.wait(lk, [this] { return m_pending || m_finish; }); + if (m_finish) { + break; + } + m_pending = false; + lk.unlock(); + + if (m_pending_work == DMCWorkType::Encode) { + m_entropy_encoder.reset(); + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + + // build_index_enc and conditional_index for each of the 4 mask steps + // Process in reverse order (3,2,1,0) to match Python encode order + int total_symbol_count = 0; + for (int i = 3; i >= 0; i--) { + auto out = conditional_index_part2_cuda(m_y_symbol[i], m_y_size[i], m_size_ptr); + m_y_to_encode_size[i] = *m_size_ptr; + total_symbol_count += *m_size_ptr; + CUDA_CHECK(cudaMemcpyAsync(m_y_to_encode[i]->data(), out.data_ptr(), + (*m_size_ptr) * sizeof(int16_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + } + CUDA_CHECK(cudaStreamSynchronize(at::cuda::getCurrentCUDAStream())); + + m_entropy_coder_parallel = compute_ec_parallel(total_symbol_count); + m_entropy_encoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + + // Encode in reverse order (3,2,1,0) to match Python + for (int i = 3; i >= 0; i--) { + m_entropy_encoder.encode_y(m_y_to_encode[i], m_y_to_encode_size[i]); + } + + auto t = tensor_to_vector_1d(m_z_hat_io); + m_entropy_encoder.encode_z(t, m_qp * g_ch_z, g_ch_z); + m_entropy_encoder.flush(); + } else if (m_pending_work == DMCWorkType::DecodeZ) { + m_entropy_decoder.set_entropy_coder_parallel(m_entropy_coder_parallel); + m_entropy_decoder.set_stream(m_bit_stream, m_bit_stream_size); + const int z_num = g_ch_z * m_z_height * m_z_width; + m_entropy_decoder.decode_z(z_num, m_qp * g_ch_z, g_ch_z); + + auto z_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_z_hat_io.data_ptr(), z_cpu->data(), + z_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_z_ready, at::cuda::getCurrentCUDAStream())); + } else if (m_pending_work == DMCWorkType::DecodeY) { + CUDA_CHECK(cudaStreamWaitEvent(at::cuda::getCurrentCUDAStream(), m_event_y)); + auto out = conditional_index_part2_cuda(m_y_indexes, m_y_indexes_size, m_size_ptr); + const int y_num = *m_size_ptr; + CUDA_CHECK(cudaMemcpyAsync(m_y_to_decode->data(), out.data_ptr(), + y_num * sizeof(uint8_t), cudaMemcpyDeviceToHost, + at::cuda::getCurrentCUDAStream())); + + m_entropy_decoder.decode_y(m_y_to_decode, y_num); + + auto y_cpu = m_entropy_decoder.get_decoded_tensor_cpp(); + CUDA_CHECK(cudaMemcpyAsync(m_y_decoded.data_ptr(), y_cpu->data(), + y_num * sizeof(int8_t), cudaMemcpyHostToDevice, + at::cuda::getCurrentCUDAStream())); + CUDA_CHECK(cudaEventRecord(m_event_y_ready, at::cuda::getCurrentCUDAStream())); + } else { + assert(false); + } + + { + std::lock_guard lk_result(m_mutex_result); + m_result_ready = true; + } + m_cv_result.notify_one(); + } +} diff --git a/src/layers/extensions/inference/dmci_proxy.h b/src/layers/extensions/inference/dmci_proxy.h new file mode 100644 index 0000000..8bc12a4 --- /dev/null +++ b/src/layers/extensions/inference/dmci_proxy.h @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "dmc_common.h" +#include "layers_proxy.h" + +class DMCIDecoderProxy { +public: + DMCIDecoderProxy() = default; + ~DMCIDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + ResidualBlockUpsampleProxy m_up; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + DepthConvBlockProxy m_conv3; + DepthConvBlockProxy m_conv4; + DepthConvBlockProxy m_conv5; + DepthConvBlockProxy m_conv6; + DepthConvBlockProxy m_conv7; + DepthConvBlockProxy m_conv8; + DepthConvBlockProxy m_conv9; + DepthConvBlockProxy m_conv10; + DepthConvBlockProxy m_conv11; + DepthConvBlockProxy m_conv12; + DepthConvBlockProxy m_dec_2; + + // for cuda graph + at::Tensor m_shuffle_out; +}; + +class DMCIEncoderProxy { +public: + DMCIEncoderProxy() = default; + ~DMCIEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::Tensor& quant); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_enc_1; + DepthConvBlockProxy m_enc_2_0; + DepthConvBlockProxy m_enc_2_1; + DepthConvBlockProxy m_enc_2_2; + DepthConvBlockProxy m_enc_2_3; + DepthConvBlockProxy m_enc_2_4; + DepthConvBlockProxy m_enc_2_5; + at::Tensor m_down_weight; + at::Tensor m_down_bias; + + // for cuda graph + at::Tensor m_down_out; +}; + +class DMCIHyperDecoderProxy { +public: + DMCIHyperDecoderProxy() = default; + ~DMCIHyperDecoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + ResidualBlockUpsampleProxy m_conv0; + ResidualBlockUpsampleProxy m_conv1; + DepthConvBlockProxy m_conv2; +}; + +class DMCIHyperEncoderProxy { +public: + DMCIHyperEncoderProxy() = default; + ~DMCIHyperEncoderProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + ResidualBlockWithStride2Proxy m_conv1; + ResidualBlockWithStride2Proxy m_conv2; +}; + +class DMCISpatialPriorProxy { +public: + DMCISpatialPriorProxy() = default; + ~DMCISpatialPriorProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, const at::Tensor& out_buf); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graph + at::Tensor m_conv3_out; +}; + +class DMCIYPriorFusionProxy { +public: + DMCIYPriorFusionProxy() = default; + ~DMCIYPriorFusionProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void set_param(const std::map& state_dict); + +private: + DepthConvBlockProxy m_conv0; + DepthConvBlockProxy m_conv1; + DepthConvBlockProxy m_conv2; + at::Tensor m_conv3_weight; + at::Tensor m_conv3_bias; + + // for cuda graph + at::Tensor m_conv3_out; +}; + +class DMCIProxy : public DMCCommon { +public: + static constexpr int g_ch_src = 3 * 8 * 8; + static constexpr int g_ch_enc_dec = 384; + static constexpr int g_ch_y = 256; + static constexpr int g_ch_z = 128; + + DMCIProxy(); + ~DMCIProxy(); + + py::tuple compress(const at::Tensor& x, const int qp, const int padding_b, const int padding_r); + at::Tensor decompress(const py::array_t& bit_stream, const int qp, const int height, + const int width, const int entropy_coder_parallel); + void set_param(const std::map& state_dict, const float skip_threshold); + +private: + // cuda graph related + void clear_cuda_graph(); + + at::Tensor decode_y_step_build_index(const at::Tensor& scales, const at::Tensor& mask, + at::Tensor& skip_cond_out, at::Tensor& indexes_num_out); + + // helper functions + std::tuple get_mask_4x(const at::Tensor& y); + + void pre_allocate_tensors(const int height, const int width); + + void worker(); + +private: + at::Tensor m_q_scale_enc[g_qp_num]; + at::Tensor m_q_scale_dec[g_qp_num]; + at::Tensor m_q_scale_y_enc[g_qp_num]; + at::Tensor m_q_scale_y_dec[g_qp_num]; + + DMCIEncoderProxy m_encoder; + DMCIHyperEncoderProxy m_hyper_encoder; + DMCIHyperDecoderProxy m_hyper_decoder; + DMCIYPriorFusionProxy m_y_prior_fusion; + ConvParam m_y_spatial_prior_reduction; + DepthConvBlockProxy m_y_spatial_prior_adaptor_1; + DepthConvBlockProxy m_y_spatial_prior_adaptor_2; + DepthConvBlockProxy m_y_spatial_prior_adaptor_3; + DMCISpatialPriorProxy m_y_spatial_prior; + DMCIDecoderProxy m_decoder; + + float m_skip_threshold{ 0.f }; + + bool m_finish{ false }; + bool m_result_ready{ false }; + std::thread m_thread; + std::mutex m_mutex_result; + std::mutex m_mutex_pending; + std::condition_variable m_cv_pending; + std::condition_variable m_cv_result; + bool m_pending{ false }; + DMCWorkType m_pending_work; + + uint8_t* m_bit_stream{ nullptr }; + int m_bit_stream_size{ 0 }; + int m_z_width{ 0 }; + int m_z_height{ 0 }; + + cudaEvent_t m_event_y; + cudaEvent_t m_event_z_ready; + cudaEvent_t m_event_y_ready; + int* m_size_ptr{ nullptr }; + + int m_qp{ 0 }; + std::shared_ptr> m_y_to_encode[4]{ nullptr }; + std::shared_ptr> m_y_to_decode{ nullptr }; + int m_y_to_encode_size[4]{ 0 }; + + at::ScalarType m_dtype; + at::Device m_device{ at::kCUDA }; + + // for cuda graph + int m_H8{ 0 }; + int m_W8{ 0 }; + cudaGraphExec_t m_gexec_enc_0[g_qp_num]{ nullptr }; + cudaGraphExec_t m_gexec_enc_1[g_qp_num]{ nullptr }; + cudaGraphExec_t m_gexec_dec_0{ nullptr }; + cudaGraphExec_t m_gexec_dec_1{ nullptr }; + cudaGraphExec_t m_gexec_dec_2{ nullptr }; + cudaGraphExec_t m_gexec_dec_3{ nullptr }; + cudaGraphExec_t m_gexec_dec_4[g_qp_num]{ nullptr }; + at::Tensor m_mask_0; + at::Tensor m_mask_1; + at::Tensor m_mask_2; + at::Tensor m_mask_3; + at::Tensor m_enc_unshuffle_out; + at::Tensor m_y; + at::Tensor m_y_pad; + at::Tensor m_z_hat; + at::Tensor m_z_hat_io; + at::Tensor m_hyper_params; + at::Tensor m_cropped_params; + at::Tensor m_y_q; + at::Tensor m_y_hat; + at::Tensor m_s_hat; + at::Tensor m_reduced_params; + at::Tensor m_y_q_w; + at::Tensor m_s_w; + at::Tensor m_y_symbol[4]; + at::Tensor m_y_symbol_prev; + at::Tensor m_skip_cond; + at::Tensor m_y_size[4]; + at::Tensor m_y_num; + at::Tensor m_x_hat; + at::Tensor m_y_q_r; + at::Tensor m_scales_r; + at::Tensor m_y_decoded; + at::Tensor m_y_indexes; + at::Tensor m_y_indexes_prev; + at::Tensor m_y_indexes_skip_cond; + at::Tensor m_y_indexes_size; + at::Tensor m_y_indexes_num; + at::Tensor m_spatial_prior_out; + + // concatenated tensor for spatial prior adaptor input + at::Tensor m_cat_spatial_prior_adaptor; + at::Tensor m_y_hat_so_far; // view into m_cat_spatial_prior_adaptor +}; diff --git a/src/layers/extensions/inference/elementwise/cat_and_pad.cu b/src/layers/extensions/inference/elementwise/cat_and_pad.cu new file mode 100644 index 0000000..f2cf456 --- /dev/null +++ b/src/layers/extensions/inference/elementwise/cat_and_pad.cu @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "../common_cu.h" +#include "../def_elementwise.h" + +__global__ void pad_and_unshuffle_8_kernel(GPUTensor4D out, const GPUTensor4D x, + const int padB, const int padR, const CudaCHW chw) +{ + // C, H, and W are the shape of output tensor + const auto [c, h, w] = global_idx_chw(); + const int originalH = chw.H * 8 - padB; + const int originalW = chw.W * 8 - padR; + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + const int src_c0 = c0 / (8 * 8); + const int src_c1 = c1 / (8 * 8); + int src_h0 = h * 8 + (c0 % (8 * 8)) / 8; + int src_h1 = h * 8 + (c1 % (8 * 8)) / 8; + int src_w0 = w * 8 + (c0 % (8 * 8)) % 8; + int src_w1 = w * 8 + (c1 % (8 * 8)) % 8; + src_h0 = min(src_h0, originalH - 1); + src_h1 = min(src_h1, originalH - 1); + src_w0 = min(src_w0, originalW - 1); + src_w1 = min(src_w1, originalW - 1); + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + store2(&out[0][c0][h][w], x[0][src_c0][src_h0][src_w0], x[0][src_c1][src_h1][src_w1]); + } +} + +at::Tensor pad_and_unshuffle_8_cuda(const at::Tensor& x, const int padB, const int padR, + at::Tensor& out_buf) +{ + const at::IntArrayRef x_shape = x.sizes(); + const int C = x_shape[1] * 8 * 8; + const int H = (x_shape[2] + padB) / 8; + const int W = (x_shape[3] + padR) / 8; + cudaLaunchConfig_t config; + CudaCHW chw; + if (C == 3 * 8 * 8) { + std::tie(config, chw) = get_kernel_config_4D<2, 16, 4, 4>(C, H, W); + } else { + std::tie(config, chw) = get_kernel_config_4D<2, 256, 1, 1>(C, H, W); + } + + cudaLaunchKernelEx(&config, &pad_and_unshuffle_8_kernel, out_buf, x, padB, padR, chw); + + return out_buf; +} + +__global__ void replicate_pad_kernel(GPUTensor4D out, const GPUTensor4D x, + const int padB, const int padR, const CudaCHW chw) +{ + // C, H, and W are the shape of output tensor + const auto [c, h, w] = global_idx_chw(); + const int originalH = chw.H - padB; + const int originalW = chw.W - padR; + const int src_h = min(h, originalH - 1); + const int src_w = min(w, originalW - 1); + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + out[0][c][h][w] = x[0][c][src_h][src_w]; + } +} + +at::Tensor replicate_pad_cuda(const at::Tensor& x, const int padB, const int padR, at::Tensor& out_buf) +{ + const at::IntArrayRef x_shape = x.sizes(); + const int C = x_shape[1]; + const int H = x_shape[2] + padB; + const int W = x_shape[3] + padR; + if (C <= 4) { + auto [config, chw] = get_kernel_config_4D<1, 4, 16, 16>(C, H, W); + + cudaLaunchKernelEx(&config, &replicate_pad_kernel, out_buf, x, padB, padR, chw); + } else { + auto [config, chw] = get_kernel_config_4D<1>(C, H, W); + + cudaLaunchKernelEx(&config, &replicate_pad_kernel, out_buf, x, padB, padR, chw); + } + return out_buf; +} + +__global__ void slice_kernel(GPUTensor4D out, const GPUTensor4D x, const CudaCHW chw) +{ + // C, H, and W are the shape of output tensor + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _x0; + at::Half _x1; + load2(&x[0][c0][h][w], _x0, _x1); + store2(&out[0][c0][h][w], _x0, _x1); + } +} + +at::Tensor slice_cuda(const at::Tensor& x, const int H, const int W, at::Tensor& out_buf) +{ + const int C = x.size(1); + auto [config, chw] = get_kernel_config_4D<2>(C, H, W); + + cudaLaunchKernelEx(&config, &slice_kernel, out_buf, x, chw); + return out_buf; +} diff --git a/src/layers/extensions/inference/elementwise/shuffle.cu b/src/layers/extensions/inference/elementwise/shuffle.cu new file mode 100644 index 0000000..1c642e5 --- /dev/null +++ b/src/layers/extensions/inference/elementwise/shuffle.cu @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "../common_cu.h" +#include "../def_elementwise.h" + +__global__ void pixel_shuffle_2_kernel(GPUTensor4D out, const GPUTensor4D x, + const CudaCHW chw) +{ + // C, H, and W are the shape of out tensor + const auto [c, h, w] = global_idx_chw(); + const int src_c = c * 2 * 2 + (h % 2) * 2 + (w % 2); + const int src_h = h / 2; + const int src_w = w / 2; + cudaGDC(); + + if (c < chw.C && w < chw.W && h < chw.H) { + out[0][c][h][w] = x[0][src_c][src_h][src_w]; + } +} + +__forceinline__ void pixel_shuffle_2_dispatcher(at::Tensor& out, const at::Tensor& x, const int C, + const int H, const int W) +{ + auto [config, chw] = get_kernel_config_4D<1, 4, 8, 8>(C, H, W); + cudaLaunchKernelEx(&config, &pixel_shuffle_2_kernel, out, x, chw); +} + +at::Tensor pixel_shuffle_2_cuda(const at::Tensor& x, at::Tensor& out_buf) +{ + const at::IntArrayRef x_shape = x.sizes(); + const int B = x_shape[0]; + const int C = x_shape[1] / 4; + const int H = x_shape[2] * 2; + const int W = x_shape[3] * 2; + pixel_shuffle_2_dispatcher(out_buf, x, C, H, W); + return out_buf; +} + +template +__global__ void pixel_shuffle_8_kernel(GPUTensor4D out, const GPUTensor4D x, + const CudaCHW chw) +{ + // C, H, and W are the shape of out tensor + const auto [c, h, w] = global_idx_chw(); + const int src_c = c * 8 * 8 + (h % 8) * 8 + (w % 8); + const int src_h = h / 8; + const int src_w = w / 8; + cudaGDC(); + + if (c < chw.C && w < chw.W && h < chw.H) { + at::Half _out = x[0][src_c][src_h][src_w]; + if constexpr (clamp) { + _out = max(_out, static_cast(-0.5f)); + _out = min(_out, static_cast(0.5f)); + } + out[0][c][h][w] = _out; + } +} + +__forceinline__ void pixel_shuffle_8_dispatcher(at::Tensor& out, const at::Tensor& x, const int C, + const int H, const int W, bool clamp) +{ + auto [config, chw] = get_kernel_config_4D<1, 4, 8, 8>(C, H, W); + + if (clamp) { + cudaLaunchKernelEx(&config, &pixel_shuffle_8_kernel, out, x, chw); + } else { + cudaLaunchKernelEx(&config, &pixel_shuffle_8_kernel, out, x, chw); + } +} + +template +__global__ void pixel_shuffle_8_out_3_kernel(GPUTensor4D out, + const GPUTensor4D x, const CudaCHW chw) +{ + // C, H, and W are the shape of out tensor + const auto [c, h, w] = global_idx_chw(); + const int c0 = c + 0; + const int c1 = c + 1; + const int c2 = c + 2; + const int src_c0 = c0 * 8 * 8 + (h % 8) * 8 + (w % 8); + const int src_c1 = c1 * 8 * 8 + (h % 8) * 8 + (w % 8); + const int src_c2 = c2 * 8 * 8 + (h % 8) * 8 + (w % 8); + const int src_h = h / 8; + const int src_w = w / 8; + cudaGDC(); + + if (c < chw.C && w < chw.W && h < chw.H) { + at::Half _out0 = x[0][src_c0][src_h][src_w]; + at::Half _out1 = x[0][src_c1][src_h][src_w]; + at::Half _out2 = x[0][src_c2][src_h][src_w]; + if constexpr (clamp) { + _out0 = max(_out0, static_cast(-0.5f)); + _out0 = min(_out0, static_cast(0.5f)); + _out1 = max(_out1, static_cast(-0.5f)); + _out1 = min(_out1, static_cast(0.5f)); + _out2 = max(_out2, static_cast(-0.5f)); + _out2 = min(_out2, static_cast(0.5f)); + } + out[0][c0][h][w] = _out0; + out[0][c1][h][w] = _out1; + out[0][c2][h][w] = _out2; + } +} + +__forceinline__ void pixel_shuffle_8_out_3_dispatcher(at::Tensor& out, const at::Tensor& x, + const int C, const int H, const int W, bool clamp) +{ + auto [config, chw] = get_kernel_config_4D<1, 1, 16, 16>(C, H, W); + + if (clamp) { + cudaLaunchKernelEx(&config, &pixel_shuffle_8_out_3_kernel, out, x, chw); + } else { + cudaLaunchKernelEx(&config, &pixel_shuffle_8_out_3_kernel, out, x, chw); + } +} + +at::Tensor pixel_shuffle_8_cuda(const at::Tensor& x, bool clamp, at::Tensor& out_buf) +{ + const at::IntArrayRef x_shape = x.sizes(); + const int B = x_shape[0]; + const int C = x_shape[1] / 64; + const int H = x_shape[2] * 8; + const int W = x_shape[3] * 8; + if (C == 3) { + pixel_shuffle_8_out_3_dispatcher(out_buf, x, C / 3, H, W, clamp); + } else { + pixel_shuffle_8_dispatcher(out_buf, x, C, H, W, clamp); + } + return out_buf; +} + +template +__global__ void pixel_unshuffle_kernel(GPUTensor4D out, const GPUTensor4D x, + const CudaCHW chw) +{ + // C, H, and W are the shape of output tensor + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + const int src_c0 = c0 / (downscale_factor * downscale_factor); + const int src_c1 = c1 / (downscale_factor * downscale_factor); + const int src_h0 = + h * downscale_factor + (c0 % (downscale_factor * downscale_factor)) / downscale_factor; + const int src_h1 = + h * downscale_factor + (c1 % (downscale_factor * downscale_factor)) / downscale_factor; + const int src_w0 = + w * downscale_factor + (c0 % (downscale_factor * downscale_factor)) % downscale_factor; + const int src_w1 = + w * downscale_factor + (c1 % (downscale_factor * downscale_factor)) % downscale_factor; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + store2(&out[0][c0][h][w], x[0][src_c0][src_h0][src_w0], x[0][src_c1][src_h1][src_w1]); + } +} + +__forceinline__ void pixel_unshuffle_dispatcher(at::Tensor& out, const at::Tensor& x, + const int downscale_factor, const int C, + const int H, const int W) +{ + // good shape for 8x unshuffle, but may not be optimal for others + auto [config, chw] = get_kernel_config_4D<1, 16, 4, 4>(C, H, W); + + if (downscale_factor == 2) { + cudaLaunchKernelEx(&config, &pixel_unshuffle_kernel<2>, out, x, chw); + } else if (downscale_factor == 4) { + cudaLaunchKernelEx(&config, &pixel_unshuffle_kernel<4>, out, x, chw); + } else if (downscale_factor == 8) { + cudaLaunchKernelEx(&config, &pixel_unshuffle_kernel<8>, out, x, chw); + } else { + assert(false); + } +} + +at::Tensor pixel_unshuffle_cuda(const at::Tensor& x, const int downscale_factor, at::Tensor& out_buf) +{ + const at::IntArrayRef x_shape = x.sizes(); + const int C = x_shape[1] * downscale_factor * downscale_factor; + const int H = x_shape[2] / downscale_factor; + const int W = x_shape[3] / downscale_factor; + pixel_unshuffle_dispatcher(out_buf, x, downscale_factor, C / 2, H, W); + return out_buf; +} diff --git a/src/layers/extensions/inference/elementwise/stream.cu b/src/layers/extensions/inference/elementwise/stream.cu new file mode 100644 index 0000000..e47f352 --- /dev/null +++ b/src/layers/extensions/inference/elementwise/stream.cu @@ -0,0 +1,962 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "../common_cu.h" +#include "../cuda_check.h" +#include "../def_elementwise.h" + +__global__ void add_and_multiply_broadcast_kernel(GPUTensor4D out, + const GPUTensor4D x0, + const GPUTensor4D x1, + const GPUTensor1D q, const CudaCHW chw) +{ + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _x0_0; + at::Half _x0_1; + load2(&x0[0][c0][h][w], _x0_0, _x0_1); + at::Half _x1_0; + at::Half _x1_1; + load2(&x1[0][c0][h][w], _x1_0, _x1_1); + at::Half _q_0 = q[c0]; + at::Half _q_1 = q[c1]; + store2(&out[0][c0][h][w], (_x0_0 + _x1_0) * _q_0, (_x0_1 + _x1_1) * _q_1); + } +} + +at::Tensor add_and_multiply_broadcast_cuda(const at::Tensor& x0, const at::Tensor& x1, + const at::Tensor& q, at::Tensor& out_buf) +{ + auto [config, chw] = get_kernel_config_4D<2>(x0); + + cudaLaunchKernelEx(&config, &add_and_multiply_broadcast_kernel, out_buf, x0, x1, q, chw); + return out_buf; +} + +__global__ void add_and_multiply_with_clamp_min_inplace_kernel(GPUTensor4D x0, + const GPUTensor4D x1, + const GPUTensor4D q, + const CudaCHW chw) +{ + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _x0_0; + at::Half _x0_1; + load2(&x0[0][c0][h][w], _x0_0, _x0_1); + at::Half _x1_0; + at::Half _x1_1; + load2(&x1[0][c0][h][w], _x1_0, _x1_1); + at::Half _q_0; + at::Half _q_1; + load2(&q[0][c0][h][w], _q_0, _q_1); + _q_0 = max(_q_0, static_cast(0.5f)); + _q_1 = max(_q_1, static_cast(0.5f)); + _x0_0 = (_x0_0 + _x1_0) * _q_0; + _x0_1 = (_x0_1 + _x1_1) * _q_1; + store2(&x0[0][c0][h][w], _x0_0, _x0_1); + } +} + +at::Tensor add_and_multiply_with_clamp_min_inplace_cuda(at::Tensor& x0, const at::Tensor& x1, + const at::Tensor& q) +{ + auto [config, chw] = get_kernel_config_4D<2>(x0); + + cudaLaunchKernelEx(&config, &add_and_multiply_with_clamp_min_inplace_kernel, x0, x1, q, chw); + return x0; +} + +__forceinline__ __device__ at::Half scale_to_index(at::Half scale, const at::Half scale_min, + const at::Half scale_max, + const at::Half log_scale_min, + const at::Half log_step_recip) +{ + scale = max(scale, scale_min); + scale = min(scale, scale_max); + scale = log(scale) - log_scale_min; + scale = scale * log_step_recip; + return scale; +} + +__global__ void build_index_dec_kernel(GPUTensor1D out, GPUTensor1D cond_out, + const GPUTensor4D scales, + const at::Half skip_thres_half, const CudaCHW chw) +{ + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + const int n0 = (h * chw.W * chw.C + w * chw.C + c) * 2 + 0; + const int n1 = (h * chw.W * chw.C + w * chw.C + c) * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _scale0; + at::Half _scale1; + load2(&scales[0][c0][h][w], _scale0, _scale1); + at::Half _index0 = + scale_to_index(_scale0, SCALE_MIN, SCALE_MAX, LOG_SCALE_MIN, LOG_SCALE_STEP_RECIP); + at::Half _index1 = + scale_to_index(_scale1, SCALE_MIN, SCALE_MAX, LOG_SCALE_MIN, LOG_SCALE_STEP_RECIP); + uint8_t _out0 = to_uint8(_index0); + uint8_t _out1 = to_uint8(_index1); + store2(&out[n0], _out0, _out1); + bool _cond0 = _scale0 > skip_thres_half; + bool _cond1 = _scale1 > skip_thres_half; + store2(&cond_out[n0], _cond0, _cond1); + } +} + +std::tuple build_index_dec_cuda(const at::Tensor& scales, + const float skip_thres_float, + const at::optional& fx, + const int32_t skip_thres_int, + at::Tensor& out_buf, at::Tensor& cond_out_buf) +{ + auto [config, chw] = get_kernel_config_4D<2>(scales); + assert(scales.scalar_type() == at::kHalf); + cudaLaunchKernelEx(&config, &build_index_dec_kernel, out_buf, cond_out_buf, scales, + skip_thres_float, chw); + return { out_buf, cond_out_buf }; +} + +__global__ void build_index_enc_kernel(GPUTensor1D out, GPUTensor1D cond_out, + const GPUTensor4D symbols, + const GPUTensor4D scales, + const at::Half skip_thres_half, const CudaCHW chw) +{ + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + const int n0 = (h * chw.W * chw.C + w * chw.C + c) * 2 + 0; + const int n1 = (h * chw.W * chw.C + w * chw.C + c) * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _scale0; + at::Half _scale1; + load2(&scales[0][c0][h][w], _scale0, _scale1); + at::Half _symbol0; + at::Half _symbol1; + load2(&symbols[0][c0][h][w], _symbol0, _symbol1); + at::Half _index0 = + scale_to_index(_scale0, SCALE_MIN, SCALE_MAX, LOG_SCALE_MIN, LOG_SCALE_STEP_RECIP); + at::Half _index1 = + scale_to_index(_scale1, SCALE_MIN, SCALE_MAX, LOG_SCALE_MIN, LOG_SCALE_STEP_RECIP); + + int16_t _out0 = (to_int16(_symbol0) << 8) + to_int16(_index0); + int16_t _out1 = (to_int16(_symbol1) << 8) + to_int16(_index1); + store2(&out[n0], _out0, _out1); + bool _cond0 = _scale0 > skip_thres_half; + bool _cond1 = _scale1 > skip_thres_half; + store2(&cond_out[n0], _cond0, _cond1); + } +} + +std::tuple +build_index_enc_cuda(const at::Tensor& symbols, const at::Tensor& scales, + const float skip_thres_float, const at::optional& fx, + const int32_t skip_thres_int, at::Tensor& out_buf, at::Tensor& cond_out_buf) +{ + auto [config, chw] = get_kernel_config_4D<2>(scales); + assert(scales.scalar_type() == at::kHalf); + cudaLaunchKernelEx(&config, &build_index_enc_kernel, out_buf, cond_out_buf, symbols, scales, + skip_thres_float, chw); + return { out_buf, cond_out_buf }; +} + +template +__global__ void conditional_index_step1_kernel(GPUTensor2D num, const GPUTensor1D m, + const int N) +{ + __shared__ int s_sum[THREAD_NUM1]; + const int tidx = threadIdx.x; + const int bidx = blockIdx.x; + + const int start_idx = PER_THREAD_NUM * (bidx * THREAD_NUM1 + tidx); + const int end_idx = min(start_idx + PER_THREAD_NUM, N); + cudaGDC(); + + int s = 0; + for (int i = start_idx; i < end_idx; i++) { + if (m[i]) { + s++; + } + } + s_sum[tidx] = s; + __syncthreads(); + + // calculate prefix sum + int curr_group_size_log2 = 1; + int curr_group_size = 1 << curr_group_size_log2; + while (curr_group_size <= THREAD_NUM1) { + if (tidx < THREAD_NUM1 / 2) { + const int half_group_size_log2 = curr_group_size_log2 - 1; + const int half_group_size = 1 << half_group_size_log2; + const int start_idx = tidx >> half_group_size_log2 << curr_group_size_log2; + const int src_idx = start_idx + (half_group_size - 1); + const int dst_idx = + start_idx + half_group_size + (tidx & ((1 << half_group_size_log2) - 1)); + s_sum[dst_idx] += s_sum[src_idx]; + } + + curr_group_size_log2++; + curr_group_size <<= 1; + __syncthreads(); + } + + num[bidx][tidx] = s_sum[tidx]; +} + +template +__global__ void conditional_index_step2_kernel(GPUTensor2D num, GPUTensor1D total_num, + const int N1) +{ + __shared__ int s_sum[THREAD_NUM2]; + const int tidx = threadIdx.x; + cudaGDC(); + + if (tidx < N1) { + s_sum[tidx] = num[tidx][THREAD_NUM1 - 1]; + } else { + s_sum[tidx] = 0; + } + __syncthreads(); + + // calculate prefix sum + int curr_group_size_log2 = 1; + int curr_group_size = 1 << curr_group_size_log2; + while (curr_group_size <= THREAD_NUM2) { + if (tidx < THREAD_NUM2 / 2) { + const int half_group_size_log2 = curr_group_size_log2 - 1; + const int half_group_size = 1 << half_group_size_log2; + const int start_idx = tidx >> half_group_size_log2 << curr_group_size_log2; + const int src_idx = start_idx + (half_group_size - 1); + const int dst_idx = + start_idx + half_group_size + (tidx & ((1 << half_group_size_log2) - 1)); + s_sum[dst_idx] += s_sum[src_idx]; + } + + curr_group_size_log2++; + curr_group_size <<= 1; + __syncthreads(); + } + + if (tidx < N1) { + num[tidx][THREAD_NUM1 - 1] = s_sum[tidx]; + } + + if (tidx == 0) { + total_num[0] = s_sum[THREAD_NUM2 - 1]; + } +} + +template +__global__ void conditional_index_step3_kernel(GPUTensor1D out, const GPUTensor2D num, + const GPUTensor1D x, const GPUTensor1D m, + const int N) +{ + const int tidx = threadIdx.x; + const int bidx = blockIdx.x; + + const int start_idx = PER_THREAD_NUM * (bidx * THREAD_NUM1 + tidx); + const int end_idx = min(start_idx + PER_THREAD_NUM, N); + cudaGDC(); + + // set according to prefix sum + int curr_dst_idx = tidx > 0 ? num[bidx][tidx - 1] : 0; + curr_dst_idx += (bidx > 0 ? num[bidx - 1][THREAD_NUM1 - 1] : 0); + for (int i = start_idx; i < end_idx; i++) { + if (m[i]) { + out[curr_dst_idx] = x[i]; + curr_dst_idx++; + } + } +} + +std::tuple +conditional_index_part1_cuda(const at::Tensor& x, const at::Tensor& m, at::Tensor& out_buf, + at::Tensor& total_num_buf, at::Tensor& num_buf) +{ + const int N = x.numel(); + const int block_num = (N + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + assert(block_num <= COND_KERNEL_THREAD_NUM2); + + static_assert(COND_KERNEL_THREAD_NUM1 == 1024 || COND_KERNEL_THREAD_NUM1 == 512 + || COND_KERNEL_THREAD_NUM1 == 256 || COND_KERNEL_THREAD_NUM1 == 128); + + cudaLaunchConfig_t config1; + config1.gridDim = block_num; + config1.blockDim = COND_KERNEL_THREAD_NUM1; + config1.dynamicSmemBytes = 0; + config1.stream = at::cuda::getCurrentCUDAStream(); + auto attr = get_cuda_launch_attribute(); + config1.attrs = &attr; + config1.numAttrs = 1; + + cudaLaunchConfig_t config2; + config2.gridDim = 1; + config2.blockDim = COND_KERNEL_THREAD_NUM2; + config2.dynamicSmemBytes = 0; + config2.stream = at::cuda::getCurrentCUDAStream(); + config2.attrs = &attr; + config2.numAttrs = 1; + + cudaLaunchKernelEx( + &config1, &conditional_index_step1_kernel, + num_buf, m, N); + cudaLaunchKernelEx( + &config2, &conditional_index_step2_kernel, + num_buf, total_num_buf, block_num); + + if (x.dtype() == at::kShort) { + cudaLaunchKernelEx( + &config1, + &conditional_index_step3_kernel, + out_buf, num_buf, x, m, N); + } else if (x.dtype() == at::kByte) { + cudaLaunchKernelEx( + &config1, + &conditional_index_step3_kernel, + out_buf, num_buf, x, m, N); + } else if (x.dtype() == at::kChar) { + cudaLaunchKernelEx( + &config1, + &conditional_index_step3_kernel, + out_buf, num_buf, x, m, N); + } else { + assert(false); + } + + return { out_buf, total_num_buf, num_buf }; +} + +at::Tensor conditional_index_part2_cuda(const at::Tensor& x, const at::Tensor& s, int* size_ptr) +{ + auto stream = at::cuda::getCurrentCUDAStream(); + if (size_ptr == nullptr) { + int s_cpu; + CUDA_CHECK(cudaMemcpyAsync(&s_cpu, s.data_ptr(), sizeof(int), cudaMemcpyDeviceToHost, + stream)); + CUDA_CHECK(cudaStreamSynchronize(stream)); + auto out = x.slice(0, 0, s_cpu); + return out; + } + CUDA_CHECK(cudaMemcpyAsync(size_ptr, s.data_ptr(), sizeof(int), cudaMemcpyDeviceToHost, stream)); + CUDA_CHECK(cudaStreamSynchronize(stream)); + auto out = x.slice(0, 0, *size_ptr); + return out; +} + +template +__global__ void conditional_recover_with_type_conversion_kernel(GPUTensor1D out, + const GPUTensor2D num, + const GPUTensor1D x, + const GPUTensor1D m, const int N) +{ + const int tidx = threadIdx.x; + const int bidx = blockIdx.x; + + const int start_idx = PER_THREAD_NUM * (bidx * THREAD_NUM1 + tidx); + const int end_idx = min(start_idx + PER_THREAD_NUM, N); + cudaGDC(); + + // set according to prefix sum + int curr_src_idx = tidx > 0 ? num[bidx][tidx - 1] : 0; + curr_src_idx += (bidx > 0 ? num[bidx - 1][THREAD_NUM1 - 1] : 0); + for (int i = start_idx; i < end_idx; i++) { + if (m[i]) { + out[i] = static_cast(x[curr_src_idx]); + curr_src_idx++; + } else { + out[i] = static_cast(0); + } + } +} + +at::Tensor conditional_recover_with_type_conversion_cuda(const at::Tensor& x, const at::Tensor& m, + const at::Tensor& num, + const at::ScalarType dtype, at::Tensor& out_buf) +{ + assert(x.dtype() == at::kChar); + const int N = m.numel(); + const int block_num = (N + COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM - 1) + / (COND_KERNEL_THREAD_NUM1 * COND_KERNEL_PER_THREAD_NUM); + static_assert(COND_KERNEL_THREAD_NUM1 == 1024 || COND_KERNEL_THREAD_NUM1 == 512 + || COND_KERNEL_THREAD_NUM1 == 256 || COND_KERNEL_THREAD_NUM1 == 128); + + cudaLaunchConfig_t config1; + config1.gridDim = block_num; + config1.blockDim = COND_KERNEL_THREAD_NUM1; + config1.dynamicSmemBytes = 0; + config1.stream = at::cuda::getCurrentCUDAStream(); + auto attr = get_cuda_launch_attribute(); + config1.attrs = &attr; + config1.numAttrs = 1; + + if (dtype == at::kHalf) { + cudaLaunchKernelEx( + &config1, + &conditional_recover_with_type_conversion_kernel, + out_buf, num, x, m, N); + } else if (dtype == at::kChar) { + cudaLaunchKernelEx( + &config1, + &conditional_recover_with_type_conversion_kernel, + out_buf, num, x, m, N); + } else { + assert(false); + } + + return out_buf; +} + +__global__ void divide_with_clamp_inplace_kernel(GPUTensor4D y, + const GPUTensor4D q, const CudaCHW chw) +{ + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _y0; + at::Half _y1; + load2(&y[0][c0][h][w], _y0, _y1); + at::Half _q0; + at::Half _q1; + load2(&q[0][c0][h][w], _q0, _q1); + _q0 = max(_q0, static_cast(0.5f)); + _q1 = max(_q1, static_cast(0.5f)); + _y0 = _y0 * reciprocal(_q0); + _y1 = _y1 * reciprocal(_q1); + store2(&y[0][c0][h][w], _y0, _y1); + } +} + +at::Tensor divide_with_clamp_min_inplace_cuda(at::Tensor& y, const at::Tensor& q) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + + cudaLaunchKernelEx(&config, ÷_with_clamp_inplace_kernel, y, q, chw); + + return y; +} + +template +__global__ void int8_to_dtype_kernel(GPUTensor1D out, const GPUTensor1D x, const int N) +{ + const int n = blockIdx.x * blockDim.x + threadIdx.x; + const int n0 = n * 2 + 0; + const int n1 = n * 2 + 1; + cudaGDC(); + + if (n < N) { + int8_t _x0 = x[n0]; + int8_t _x1 = x[n1]; + store2(&out[n0], static_cast(_x0), static_cast(_x1)); + } +} + +at::Tensor int8_to_dtype_cuda(const at::Tensor& x, const at::ScalarType dtype, const int C, + const int H, const int W, at::Tensor& out_buf) +{ + auto [config, N] = get_kernel_config_1D<2>(x); + + if (dtype == at::kHalf) { + cudaLaunchKernelEx(&config, &int8_to_dtype_kernel, out_buf, x, N); + } else if (dtype == at::kShort) { + cudaLaunchKernelEx(&config, &int8_to_dtype_kernel, out_buf, x, N); + } else { + assert(false); + } + return out_buf; +} + +template +__global__ void multiply_with_broadcast_kernel(GPUTensor4D out, const GPUTensor4D a, + const GPUTensor1D b, const int C, const int N) +{ + static_assert(unrolling_factor == 1 || unrolling_factor == 2 || unrolling_factor == 4); + const int c = blockIdx.x * blockDim.x + threadIdx.x; + const int n = blockIdx.y * blockDim.y + threadIdx.y; + const int n0 = n * unrolling_factor; + cudaGDC(); + + if (c < C && n < N) { + const at::Half _b = b[c]; + if (unrolling_factor >= 1) { + out[0][c][0][n0 + 0] = a[0][c][0][n0 + 0] * _b; + } + if (unrolling_factor >= 2) { + out[0][c][0][n0 + 1] = a[0][c][0][n0 + 1] * _b; + } + if (unrolling_factor >= 4) { + out[0][c][0][n0 + 2] = a[0][c][0][n0 + 2] * _b; + out[0][c][0][n0 + 3] = a[0][c][0][n0 + 3] * _b; + } + } +} + +at::Tensor multiply_with_broadcast_cuda(const at::Tensor& a, const at::Tensor& b, at::Tensor& out_buf) +{ + auto attr = get_cuda_launch_attribute(); + + const int C = a.size(1); + int N = a.size(2) * a.size(3); + int factor; + if (N % 4 == 0) { + factor = 4; + N /= 4; + } else if (N % 2 == 0) { + factor = 2; + N /= 2; + } else { + factor = 1; + } + const int BLOCK_SIZE_C = 256; + const int BLOCK_SIZE_N = 1; + const dim3 blockDim(BLOCK_SIZE_C, BLOCK_SIZE_N); + const dim3 gridDim((C + BLOCK_SIZE_C - 1) / BLOCK_SIZE_C, (N + BLOCK_SIZE_N - 1) / BLOCK_SIZE_N); + + cudaLaunchConfig_t config; + config.gridDim = gridDim; + config.blockDim = blockDim; + config.dynamicSmemBytes = 0; + config.stream = at::cuda::getCurrentCUDAStream(); + config.attrs = &attr; + config.numAttrs = 1; + + if (factor == 4) { + cudaLaunchKernelEx(&config, &multiply_with_broadcast_kernel<4>, out_buf, a, b, C, N); + } else if (factor == 2) { + cudaLaunchKernelEx(&config, &multiply_with_broadcast_kernel<2>, out_buf, a, b, C, N); + } else { + cudaLaunchKernelEx(&config, &multiply_with_broadcast_kernel<1>, out_buf, a, b, C, N); + } + return out_buf; +} + +template +__global__ void process_with_mask_kernel(GPUTensor4D y_q, GPUTensor4D y_hat, + GPUTensor4D s_hat, const GPUTensor4D y, + const GPUTensor4D scales, + const GPUTensor4D means, + const GPUTensor4D mask, const GPUTensor4D quant, + const at::Half force_zero_thres, const CudaCHW chw) +{ + static_assert(!scale_out || !multiply); + static_assert(!multiply || add_inplace); + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + bool _mask0; + bool _mask1; + load2(&mask[0][c0][h][w], _mask0, _mask1); + at::Half _y0; + at::Half _y1; + load2(&y[0][c0][h][w], _y0, _y1); + + const at::Half _min_val = static_cast(-128.f); + const at::Half _max_val = static_cast(127.f); + + at::Half _scale0; + at::Half _scale1; + load2(&scales[0][c0][h][w], _scale0, _scale1); + at::Half _means0; + at::Half _means1; + load2(&means[0][c0][h][w], _means0, _means1); + + at::Half _s_hat0 = _scale0 * _mask0; + at::Half _s_hat1 = _scale1 * _mask1; + at::Half _means_hat0 = _means0 * _mask0; + at::Half _means_hat1 = _means1 * _mask1; + at::Half _y_res0 = (_y0 - _means_hat0) * _mask0; + at::Half _y_res1 = (_y1 - _means_hat1) * _mask1; + at::Half _y_q0 = round(_y_res0); + at::Half _y_q1 = round(_y_res1); + _y_q0 = _y_q0 * (_s_hat0 > force_zero_thres); + _y_q1 = _y_q1 * (_s_hat1 > force_zero_thres); + _y_q0 = max(min(_y_q0, _max_val), _min_val); + _y_q1 = max(min(_y_q1, _max_val), _min_val); + at::Half _y_hat0 = _y_q0 + _means_hat0; + at::Half _y_hat1 = _y_q1 + _means_hat1; + + if constexpr (add_inplace) { + at::Half _t0; + at::Half _t1; + load2(&y_q[0][c0][h][w], _t0, _t1); + store2(&y_q[0][c0][h][w], _t0 + _y_q0, _t1 + _y_q1); + } else { + store2(&y_q[0][c0][h][w], _y_q0, _y_q1); + } + + if constexpr (multiply) { + at::Half _q0; + at::Half _q1; + load2(&quant[0][c0][h][w], _q0, _q1); + _q0 = max(_q0, static_cast(0.5f)); + _q1 = max(_q1, static_cast(0.5f)); + at::Half _t0; + at::Half _t1; + load2(&y_hat[0][c0][h][w], _t0, _t1); + _y_hat0 += _t0; + _y_hat1 += _t1; + store2(&y_hat[0][c0][h][w], _y_hat0 * _q0, _y_hat1 * _q1); + } else if constexpr (add_inplace) { + at::Half _t0; + at::Half _t1; + load2(&y_hat[0][c0][h][w], _t0, _t1); + store2(&y_hat[0][c0][h][w], _y_hat0 + _t0, _y_hat1 + _t1); + } else { + store2(&y_hat[0][c0][h][w], _y_hat0, _y_hat1); + } + + if constexpr (scale_out) { + store2(&s_hat[0][c0][h][w], _s_hat0, _s_hat1); + } + } +} + +std::tuple +process_with_mask_cuda(const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, + const at::Tensor& mask, const float force_zero_thres_float, + const int32_t force_zero_thres_int, at::Tensor& y_q_buf, + at::Tensor& y_hat_buf, at::Tensor& s_hat_buf) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + assert(scales.scalar_type() == at::kHalf); + cudaLaunchKernelEx(&config, &process_with_mask_kernel<>, y_q_buf, y_hat_buf, s_hat_buf, y, + scales, means, mask, nullptr, force_zero_thres_float, chw); + + return { y_q_buf, y_hat_buf, s_hat_buf }; +} + +std::tuple process_with_mask_no_scale_add_and_multiply_inplace_cuda( + const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& y_q, at::Tensor& y_hat, const at::Tensor& quant, const float force_zero_thres_float, + const int32_t force_zero_thres_int) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + assert(scales.scalar_type() == at::kHalf); + cudaLaunchKernelEx(&config, &process_with_mask_kernel, y_q, y_hat, nullptr, + y, scales, means, mask, quant, force_zero_thres_float, chw); + + return { y_q, y_hat }; +} + +std::tuple process_with_mask_no_scale_add_inplace_cuda( + const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& y_q, at::Tensor& y_hat, const float force_zero_thres_float, + const int32_t force_zero_thres_int) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + assert(scales.scalar_type() == at::kHalf); + cudaLaunchKernelEx(&config, &process_with_mask_kernel, y_q, y_hat, nullptr, y, + scales, means, mask, nullptr, force_zero_thres_float, chw); + + return { y_q, y_hat }; +} + +std::tuple process_with_mask_no_scale_cuda( + const at::Tensor& y, const at::Tensor& scales, const at::Tensor& means, const at::Tensor& mask, + const float force_zero_thres_float, const int32_t force_zero_thres_int, at::Tensor& y_q_buf, + at::Tensor& y_hat_buf) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + assert(scales.scalar_type() == at::kHalf); + cudaLaunchKernelEx(&config, &process_with_mask_kernel, y_q_buf, y_hat_buf, nullptr, y, + scales, means, mask, nullptr, force_zero_thres_float, chw); + + return { y_q_buf, y_hat_buf }; +} + +template +__global__ void restore_y_kernel(GPUTensor4D out, const GPUTensor4D y, + const GPUTensor4D means, const GPUTensor4D mask, + const GPUTensor4D q, const CudaCHW chw) +{ + static_assert(!multiply || add_inplace); + // C, H, and W are the shape of y tensor + const auto [c, h, w] = global_idx_chw(); + const int c0 = c * 2 + 0; + const int c1 = c * 2 + 1; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + bool _mask0 = mask[0][c0][h][w]; + bool _mask1 = mask[0][c1][h][w]; + + at::Half _y0; + at::Half _y1; + load2(&y[0][c0][h][w], _y0, _y1); + at::Half _means0; + at::Half _means1; + load2(&means[0][c0][h][w], _means0, _means1); + + _y0 = (_y0 + _means0) * _mask0; + _y1 = (_y1 + _means1) * _mask1; + if constexpr (add_inplace) { + at::Half _out_0; + at::Half _out_1; + load2(&out[0][c0][h][w], _out_0, _out_1); + + _y0 = _y0 + _out_0; + _y1 = _y1 + _out_1; + if constexpr (multiply) { + at::Half _q0; + at::Half _q1; + load2(&q[0][c0][h][w], _q0, _q1); + _q0 = max(_q0, static_cast(0.5f)); + _q1 = max(_q1, static_cast(0.5f)); + _y0 = _y0 * _q0; + _y1 = _y1 * _q1; + } + } + store2(&out[0][c0][h][w], _y0, _y1); + } +} + +at::Tensor restore_y_and_add_inplace_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, at::Tensor& y_hat) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + cudaLaunchKernelEx(&config, &restore_y_kernel, y_hat, y, means, mask, nullptr, chw); + return y_hat; +} + +at::Tensor restore_y_and_add_multiply_inplace_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, at::Tensor& y_hat, + const at::Tensor& q) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + cudaLaunchKernelEx(&config, &restore_y_kernel, y_hat, y, means, mask, q, chw); + return y_hat; +} + +at::Tensor restore_y_cuda(const at::Tensor& y, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& out_buf) +{ + auto [config, chw] = get_kernel_config_4D<2>(y); + cudaLaunchKernelEx(&config, &restore_y_kernel<>, out_buf, y, means, mask, nullptr, chw); + return out_buf; +} + +template +__global__ void restore_y_4x_kernel(GPUTensor4D out, const GPUTensor4D y, + const GPUTensor4D means, const GPUTensor4D mask, + const CudaCHW chw) +{ + // C, H, and W are the shape of y tensor + const auto [c, h, w] = global_idx_chw(); + const int c1 = c; + const int c2 = c1 + chw.C; + const int c3 = c2 + chw.C; + const int c4 = c3 + chw.C; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + bool _mask1 = mask[0][c1][h][w]; + bool _mask2 = mask[0][c2][h][w]; + bool _mask3 = mask[0][c3][h][w]; + bool _mask4 = mask[0][c4][h][w]; + + at::Half _y = y[0][c][h][w]; + at::Half _t1 = (_y + means[0][c1][h][w]) * _mask1; + at::Half _t2 = (_y + means[0][c2][h][w]) * _mask2; + at::Half _t3 = (_y + means[0][c3][h][w]) * _mask3; + at::Half _t4 = (_y + means[0][c4][h][w]) * _mask4; + if constexpr (add_inplace) { + out[0][c1][h][w] = out[0][c1][h][w] + _t1; + out[0][c2][h][w] = out[0][c2][h][w] + _t2; + out[0][c3][h][w] = out[0][c3][h][w] + _t3; + out[0][c4][h][w] = out[0][c4][h][w] + _t4; + } else { + out[0][c1][h][w] = _t1; + out[0][c2][h][w] = _t2; + out[0][c3][h][w] = _t3; + out[0][c4][h][w] = _t4; + } + } +} + +at::Tensor restore_y_4x_and_add_inplace_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, at::Tensor& y_hat) +{ + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + auto [config, chw] = get_kernel_config_4D(C, H, W); + + cudaLaunchKernelEx(&config, &restore_y_4x_kernel, y_hat, y, means, mask, chw); + return y_hat; +} + +at::Tensor restore_y_4x_cuda(const at::Tensor& y, const at::Tensor& means, const at::Tensor& mask, + at::Tensor& out_buf) +{ + const int B = y.size(0); + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + + auto [config, chw] = get_kernel_config_4D(C, H, W); + + cudaLaunchKernelEx(&config, &restore_y_4x_kernel<>, out_buf, y, means, mask, chw); + return out_buf; +} + +__global__ void restore_y_4x_add_and_multiply_broadcast_kernel( + GPUTensor4D out, const GPUTensor4D y_hat_so_far, + const GPUTensor4D y, const GPUTensor4D means, const GPUTensor4D mask, + const GPUTensor1D q, const CudaCHW chw) +{ + const auto [c, h, w] = global_idx_chw(); + const int c1 = c; + const int c2 = c1 + chw.C; + const int c3 = c2 + chw.C; + const int c4 = c3 + chw.C; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + bool _mask1 = mask[0][c1][h][w]; + bool _mask2 = mask[0][c2][h][w]; + bool _mask3 = mask[0][c3][h][w]; + bool _mask4 = mask[0][c4][h][w]; + + at::Half _y = y[0][c][h][w]; + out[0][c1][h][w] = (y_hat_so_far[0][c1][h][w] + (_y + means[0][c1][h][w]) * _mask1) * q[c1]; + out[0][c2][h][w] = (y_hat_so_far[0][c2][h][w] + (_y + means[0][c2][h][w]) * _mask2) * q[c2]; + out[0][c3][h][w] = (y_hat_so_far[0][c3][h][w] + (_y + means[0][c3][h][w]) * _mask3) * q[c3]; + out[0][c4][h][w] = (y_hat_so_far[0][c4][h][w] + (_y + means[0][c4][h][w]) * _mask4) * q[c4]; + } +} + +at::Tensor restore_y_4x_add_and_multiply_broadcast_cuda(const at::Tensor& y, const at::Tensor& means, + const at::Tensor& mask, + const at::Tensor& y_hat_so_far, + const at::Tensor& q, at::Tensor& out_buf) +{ + const int C = y.size(1); + const int H = y.size(2); + const int W = y.size(3); + + auto [config, chw] = get_kernel_config_4D(C, H, W); + + cudaLaunchKernelEx(&config, &restore_y_4x_add_and_multiply_broadcast_kernel, out_buf, + y_hat_so_far, y, means, mask, q, chw); + return out_buf; +} + +__global__ void round_z_kernel(GPUTensor1D z_hat, GPUTensor1D z_int8, + const GPUTensor1D z, const int N) +{ + const int n = blockIdx.x * blockDim.x + threadIdx.x; + const int n0 = n * 2 + 0; + cudaGDC(); + + if (n < N) { + at::Half _z0; + at::Half _z1; + load2(&z[n0], _z0, _z1); + _z0 = round(_z0); + _z1 = round(_z1); + _z0 = max(_z0, static_cast(-64.f)); + _z1 = max(_z1, static_cast(-64.f)); + _z0 = min(_z0, static_cast(63.f)); + _z1 = min(_z1, static_cast(63.f)); + int8_t _z0_int8 = static_cast(_z0); + int8_t _z1_int8 = static_cast(_z1); + store2(&z_int8[n0], _z0_int8, _z1_int8); + store2(&z_hat[n0], _z0, _z1); + } +} + +std::tuple round_z_cuda(const at::Tensor& z, at::Tensor& z_hat_buf, + at::Tensor& z_int8_buf) +{ + auto [config, N] = get_kernel_config_1D<2>(z); + + cudaLaunchKernelEx(&config, &round_z_kernel, z_hat_buf, z_int8_buf, z, N); + + return { z_hat_buf, z_int8_buf }; +} + +__global__ void single_part_for_reading_4x_kernel(GPUTensor4D out, + const GPUTensor4D x, + const GPUTensor4D mask, const CudaCHW chw) +{ + // C, H, and W are the shape of out tensor + const auto [c, h, w] = global_idx_chw(); + const int c1 = c; + const int c2 = c1 + chw.C; + const int c3 = c2 + chw.C; + const int c4 = c3 + chw.C; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _x1 = x[0][c1][h][w] * mask[0][c1][h][w]; + at::Half _x2 = x[0][c2][h][w] * mask[0][c2][h][w]; + at::Half _x3 = x[0][c3][h][w] * mask[0][c3][h][w]; + at::Half _x4 = x[0][c4][h][w] * mask[0][c4][h][w]; + out[0][c][h][w] = _x1 + _x2 + _x3 + _x4; + } +} + +at::Tensor single_part_for_reading_4x_cuda(const at::Tensor& x, const at::Tensor& mask, + at::Tensor& out_buf) +{ + const int B = x.size(0); + const int C = x.size(1) / 4; + const int H = x.size(2); + const int W = x.size(3); + + auto [config, chw] = get_kernel_config_4D(C, H, W); + + cudaLaunchKernelEx(&config, &single_part_for_reading_4x_kernel, out_buf, x, mask, chw); + return out_buf; +} + +__global__ void single_part_for_writing_4x_kernel(GPUTensor4D out, + const GPUTensor4D x, const CudaCHW chw) +{ + // C, H, and W are the shape of out tensor + const auto [c, h, w] = global_idx_chw(); + const int c1 = c; + const int c2 = c1 + chw.C; + const int c3 = c2 + chw.C; + const int c4 = c3 + chw.C; + cudaGDC(); + + if (c < chw.C && h < chw.H && w < chw.W) { + at::Half _x1 = x[0][c1][h][w]; + at::Half _x2 = x[0][c2][h][w]; + at::Half _x3 = x[0][c3][h][w]; + at::Half _x4 = x[0][c4][h][w]; + out[0][c][h][w] = _x1 + _x2 + _x3 + _x4; + } +} + +at::Tensor single_part_for_writing_4x_cuda(const at::Tensor& x, at::Tensor& out_buf) +{ + const int B = x.size(0); + const int C = x.size(1) / 4; + const int H = x.size(2); + const int W = x.size(3); + + auto [config, chw] = get_kernel_config_4D(C, H, W); + + cudaLaunchKernelEx(&config, &single_part_for_writing_4x_kernel, out_buf, x, chw); + return out_buf; +} diff --git a/src/layers/extensions/inference/install.sh b/src/layers/extensions/inference/install.sh new file mode 100644 index 0000000..1e5a323 --- /dev/null +++ b/src/layers/extensions/inference/install.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +start=$(date +%s) +pip install --no-build-isolation . +end=$(date +%s) +runtime=$((end - start)) +echo "Execution time: $runtime seconds" diff --git a/src/layers/extensions/inference/layers_proxy.cpp b/src/layers/extensions/inference/layers_proxy.cpp new file mode 100644 index 0000000..ed0d3b0 --- /dev/null +++ b/src/layers/extensions/inference/layers_proxy.cpp @@ -0,0 +1,324 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +#include "common_cpp.h" +#include "def_cutlass.h" +#include "def_elementwise.h" +#include "layers_proxy.h" +#include "memory_pool.h" + +std::tuple chunk_tensors_2(const at::Tensor& x) +{ + auto out = x.chunk(2, 1); + return { out[0], out[1] }; +} + +std::tuple chunk_tensors_3(const at::Tensor& x) +{ + auto out = x.chunk(3, 1); + return { out[0], out[1], out[2] }; +} + +at::Tensor conv2d(const at::Tensor& feature, const at::Tensor& weight, const at::Tensor& bias, + const int stride, at::Tensor& out_buf) +{ + const int sm = get_gpu_sm(); + + const int kernel = weight.size(2); + if (kernel == 1 && stride == 1) { + return conv1x1_bias(sm, feature, weight, bias, out_buf); + } + return conv_bias(sm, feature, weight, bias, stride, out_buf); +} + +std::map +get_submodule_state_dict(const std::map& state_dict, const std::string& prefix) +{ + + std::map submodule_state_dict; + + for (const auto& param : state_dict) { + if (param.first.rfind(prefix, 0) == 0) { + std::string new_key = param.first.substr(prefix.size()); + submodule_state_dict[new_key] = param.second; + } + } + + return submodule_state_dict; +} + +std::tuple split_tensors_2(const at::Tensor& x, const int C1, const int C2) +{ + auto out = x.split_with_sizes({ C1, C2 }, 1); + return { out[0], out[1] }; +} + +std::tuple split_tensors_3(const at::Tensor& x, const int C1, + const int C2, const int C3) +{ + auto out = x.split_with_sizes({ C1, C2, C3 }, 1); + return { out[0], out[1], out[2] }; +} + +void ConvParam::set_param(const std::map& state_dict, const std::string& prefix) +{ + weight = state_dict.at(prefix + "weight"); + bias = state_dict.at(prefix + "bias"); +} + +at::Tensor DepthConvBlockProxy::forward(const at::Tensor& x, const at::optional& quant) +{ + const int sm = get_gpu_sm(); + + auto out = x; + if (m_adaptor) { + out = conv1x1_bias(sm, x, m_adaptor_weight, m_adaptor_bias, m_adaptor_out); + } + auto shortcut = out; + out = conv1x1_bias_wsilu(sm, out, m_dc_conv1_weight, m_dc_conv1_bias, m_dc_conv1_out); + out = d3x3(sm, out, m_dc_depth_conv_weight, m_dc_depth_conv_out); + out = conv1x1_bias_shortcut(sm, out, m_dc_conv2_weight, m_dc_conv2_bias, shortcut, m_dc_conv2_out); + + auto shortcut_ffn = out; + out = conv1x1_bias_wsilu_chunk_add(sm, out, m_ffn_conv1_weight, m_ffn_conv1_bias, + m_ffn_conv1_weight0, m_ffn_conv1_weight1, m_ffn_conv1_weight2, + m_ffn_conv1_weight3, m_ffn_conv1_bias0, m_ffn_conv1_bias1, + m_ffn_conv1_bias2, m_ffn_conv1_bias3, m_ffn_conv1_out); + if (m_shortcut) { + out = conv1x1_bias_shortcut2(sm, out, m_ffn_conv2_weight, m_ffn_conv2_bias, shortcut_ffn, + shortcut, m_ffn_conv2_out); + } else if (quant.has_value()) { + out = conv1x1_bias_shortcut_with_quant(sm, out, m_ffn_conv2_weight, m_ffn_conv2_bias, + shortcut_ffn, quant.value(), m_ffn_conv2_out); + } else { + out = conv1x1_bias_shortcut(sm, out, m_ffn_conv2_weight, m_ffn_conv2_bias, shortcut_ffn, + m_ffn_conv2_out); + } + + return out; +} + +at::Tensor DepthConvBlockProxy::pre_allocate_tensors(at::Tensor& x, const bool input_further_use, + const at::optional& out_buf) +{ + const int H = x.size(2); + const int W = x.size(3); + bool dc_input_modifiable = !m_shortcut && (!input_further_use || m_adaptor); + + auto options = m_dc_conv1_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int ch_dc = m_dc_conv1_weight.size(0); + const int C = m_dc_conv1_weight.size(1); + const int ch_ffn = m_ffn_conv2_weight.size(1); + + auto dc_input = x; + if (m_adaptor) { + const int C1 = m_adaptor_weight.size(0); + m_adaptor_out = g_tensor_pool.empty({ 1, C1, H, W }, options); + dc_input = m_adaptor_out; + } + + m_dc_conv1_out = g_tensor_pool.empty({ 1, ch_dc, H, W }, options); + m_dc_depth_conv_out = g_tensor_pool.empty_like(m_dc_conv1_out); + if (out_buf.has_value()) { + m_dc_conv2_out = out_buf.value(); + } else if (dc_input_modifiable) { + m_dc_conv2_out = dc_input; + } else { + m_dc_conv2_out = g_tensor_pool.empty({ 1, C, H, W }, options); + } + m_ffn_conv1_out = g_tensor_pool.empty({ 1, ch_ffn, H, W }, options); + m_ffn_conv2_out = m_dc_conv2_out; + + if (!input_further_use) { + if (m_adaptor || out_buf.has_value()) { + g_tensor_pool.release(x); + } + } + if (out_buf.has_value()) { + if (m_adaptor) { + g_tensor_pool.release(m_adaptor_out); + } + } + + g_tensor_pool.release(m_dc_conv1_out); + g_tensor_pool.release(m_dc_depth_conv_out); + g_tensor_pool.release(m_ffn_conv1_out); + + return m_ffn_conv2_out; +} + +void DepthConvBlockProxy::release_tensors() +{ + if (m_adaptor_out.defined()) { + g_tensor_pool.release(m_adaptor_out); + } + g_tensor_pool.release(m_ffn_conv2_out); +} + +void DepthConvBlockProxy::set_param(const std::map& state_dict, + const bool shortcut) +{ + auto it = state_dict.find("adaptor.weight"); + if (it != state_dict.end()) { + m_adaptor_weight = state_dict.at("adaptor.weight"); + m_adaptor_bias = state_dict.at("adaptor.bias"); + m_adaptor = true; + } + m_dc_conv1_weight = state_dict.at("dc.0.weight"); + m_dc_conv1_bias = state_dict.at("dc.0.bias"); + // Note: d3x3 weight is reordered from [C, 1, 3, 3] to [1, C, 3, 3]. + m_dc_depth_conv_weight = + state_dict.at("dc.2.weight").permute({ 1, 0, 2, 3 }).contiguous(at::MemoryFormat::ChannelsLast); + m_dc_conv2_weight = state_dict.at("dc.3.weight"); + m_dc_conv2_bias = at::conv2d(state_dict.at("dc.2.bias").reshape({ 1, -1, 1, 1 }), + state_dict.at("dc.3.weight")); + m_dc_conv2_bias = + m_dc_conv2_bias.index({ 0, at::indexing::Slice(), 0, 0 }) + state_dict.at("dc.3.bias"); + m_ffn_conv1_weight = state_dict.at("ffn.0.weight"); + m_ffn_conv1_bias = state_dict.at("ffn.0.bias"); + + m_ffn_conv1_weight0 = + m_ffn_conv1_weight.index({ at::indexing::Slice(0, at::nullopt, 4), at::indexing::Slice(), + at::indexing::Slice(), at::indexing::Slice() }); + m_ffn_conv1_weight1 = + m_ffn_conv1_weight.index({ at::indexing::Slice(1, at::nullopt, 4), at::indexing::Slice(), + at::indexing::Slice(), at::indexing::Slice() }); + m_ffn_conv1_weight2 = + m_ffn_conv1_weight.index({ at::indexing::Slice(2, at::nullopt, 4), at::indexing::Slice(), + at::indexing::Slice(), at::indexing::Slice() }); + m_ffn_conv1_weight3 = + m_ffn_conv1_weight.index({ at::indexing::Slice(3, at::nullopt, 4), at::indexing::Slice(), + at::indexing::Slice(), at::indexing::Slice() }); + m_ffn_conv1_bias0 = + m_ffn_conv1_bias.index({ at::indexing::Slice(0, at::nullopt, 4) }).contiguous(); + m_ffn_conv1_bias1 = + m_ffn_conv1_bias.index({ at::indexing::Slice(1, at::nullopt, 4) }).contiguous(); + m_ffn_conv1_bias2 = + m_ffn_conv1_bias.index({ at::indexing::Slice(2, at::nullopt, 4) }).contiguous(); + m_ffn_conv1_bias3 = + m_ffn_conv1_bias.index({ at::indexing::Slice(3, at::nullopt, 4) }).contiguous(); + + m_ffn_conv2_weight = state_dict.at("ffn.2.weight"); + m_ffn_conv2_bias = state_dict.at("ffn.2.bias"); + m_shortcut = shortcut; +} + +at::Tensor ResidualBlockUpsampleProxy::forward(const at::Tensor& x) +{ + auto out = m_up.forward(x); + return m_conv.forward(out); +} + +at::Tensor ResidualBlockUpsampleProxy::pre_allocate_tensors(at::Tensor& x) +{ + auto out = m_up.pre_allocate_tensors(x); + out = m_conv.pre_allocate_tensors(out); + return out; +} + +void ResidualBlockUpsampleProxy::release_tensors() +{ + m_up.release_tensors(); + m_conv.release_tensors(); +} + +void ResidualBlockUpsampleProxy::set_param(const std::map& state_dict, + const bool shortcut) +{ + m_up.set_param(get_submodule_state_dict(state_dict, "up.")); + m_conv.set_param(get_submodule_state_dict(state_dict, "conv."), shortcut); +} + +at::Tensor ResidualBlockWithStride2Proxy::forward(const at::Tensor& x) +{ + const int sm = get_gpu_sm(); + auto out = conv_bias(sm, x, m_weight, m_bias, 2, m_conv_out); + out = m_conv.forward(out); + return out; +} + +at::Tensor ResidualBlockWithStride2Proxy::pre_allocate_tensors(at::Tensor& x, + const at::optional& out_buf) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int C = m_weight.size(0); + m_conv_out = g_tensor_pool.empty({ 1, C, H / 2, W / 2 }, options); + // because we will downsample first, for the DCB, input will not be further used + return m_conv.pre_allocate_tensors(m_conv_out, false, out_buf); +} + +void ResidualBlockWithStride2Proxy::release_tensors() +{ + g_tensor_pool.release(m_conv_out); + m_conv.release_tensors(); +} + +void ResidualBlockWithStride2Proxy::set_param(const std::map& state_dict, + const bool shortcut) +{ + m_weight = state_dict.at("down.weight"); + m_weight = at::pixel_shuffle(m_weight, 2).contiguous(at::MemoryFormat::ChannelsLast); + m_bias = state_dict.at("down.bias"); + m_conv.set_param(get_submodule_state_dict(state_dict, "conv."), shortcut); +} + +at::Tensor SubpelConv2xProxy::forward(const at::Tensor& x) +{ + if (m_bias.defined()) { + auto out = conv2d(x, m_weight, m_bias, 1, m_conv_out); + return pixel_shuffle_2_cuda(out, m_shuffle_out); + } + return transposed_conv(get_gpu_sm(), x, m_weight_transposed, 2, m_conv_out); +} + +at::Tensor SubpelConv2xProxy::pre_allocate_tensors(at::Tensor& x) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int C = m_weight.size(0); + if (m_bias.defined()) { + m_conv_out = g_tensor_pool.empty({ 1, C, H, W }, options); + m_shuffle_out = g_tensor_pool.empty({ 1, C / 4, H * 2, W * 2 }, options); + return m_shuffle_out; + } + m_conv_out = g_tensor_pool.empty({ 1, C / 4, H * 2, W * 2 }, options); + return m_conv_out; +} + +at::Tensor SubpelConv2xProxy::pre_allocate_tensors(at::Tensor& x, at::Tensor& out_buf) +{ + const int H = x.size(2); + const int W = x.size(3); + auto options = m_weight.options().memory_format(at::MemoryFormat::ChannelsLast); + const int C = m_weight.size(0); + if (m_bias.defined()) { + m_conv_out = g_tensor_pool.empty({ 1, C, H, W }, options); + m_shuffle_out = out_buf; + return m_shuffle_out; + } + m_conv_out = out_buf; + return m_conv_out; +} + +void SubpelConv2xProxy::release_tensors() +{ + g_tensor_pool.release(m_conv_out); + g_tensor_pool.release(m_shuffle_out); +} + +void SubpelConv2xProxy::set_param(const std::map& state_dict) +{ + m_weight = state_dict.at("conv.0.weight"); + auto it = state_dict.find("conv.0.bias"); + if (it != state_dict.end()) { + m_bias = state_dict.at("conv.0.bias"); + } else { + m_weight_transposed = + at::pixel_shuffle(m_weight.permute({ 1, 0, 2, 3 }), 2).contiguous(at::MemoryFormat::ChannelsLast); + } +} diff --git a/src/layers/extensions/inference/layers_proxy.h b/src/layers/extensions/inference/layers_proxy.h new file mode 100644 index 0000000..39704b9 --- /dev/null +++ b/src/layers/extensions/inference/layers_proxy.h @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +#include "def_const.h" +#include "py_rans.h" + +std::tuple chunk_tensors_2(const at::Tensor& x); +std::tuple chunk_tensors_3(const at::Tensor& x); +std::map get_submodule_state_dict(const std::map& state_dict, + const std::string& prefix); +std::tuple split_tensors_2(const at::Tensor& x, const int C1, const int C2); +std::tuple split_tensors_3(const at::Tensor& x, const int C1, + const int C2, const int C3); + +class ConvParam { +public: + at::Tensor weight; + at::Tensor bias; + + ConvParam() = default; + ~ConvParam() = default; + + void set_param(const std::map& state_dict, const std::string& prefix); +}; + +class DepthConvBlockProxy { +public: + DepthConvBlockProxy() = default; + ~DepthConvBlockProxy() = default; + + at::Tensor forward(const at::Tensor& x, const at::optional& quant = at::nullopt); + at::Tensor pre_allocate_tensors(at::Tensor& x, const bool input_further_use = false, + const at::optional& out_buf = at::nullopt); + void release_tensors(); + void set_param(const std::map& state_dict, const bool shortcut = false); + +private: + at::Tensor m_adaptor_weight; + at::Tensor m_adaptor_bias; + at::Tensor m_dc_conv1_weight; + at::Tensor m_dc_conv1_bias; + at::Tensor m_dc_depth_conv_weight; + at::Tensor m_dc_conv2_weight; + at::Tensor m_dc_conv2_bias; + at::Tensor m_ffn_conv1_weight; + at::Tensor m_ffn_conv1_bias; + at::Tensor m_ffn_conv1_weight0; + at::Tensor m_ffn_conv1_weight1; + at::Tensor m_ffn_conv1_weight2; + at::Tensor m_ffn_conv1_weight3; + at::Tensor m_ffn_conv1_bias0; + at::Tensor m_ffn_conv1_bias1; + at::Tensor m_ffn_conv1_bias2; + at::Tensor m_ffn_conv1_bias3; + at::Tensor m_ffn_conv2_weight; + at::Tensor m_ffn_conv2_bias; + bool m_adaptor{ false }; + bool m_shortcut{ false }; + + // for cuda graphs + at::Tensor m_adaptor_out; + at::Tensor m_dc_conv1_out; + at::Tensor m_dc_depth_conv_out; + at::Tensor m_dc_conv2_out; + at::Tensor m_ffn_conv1_out; + at::Tensor m_ffn_conv2_out; +}; + +class SubpelConv2xProxy { +public: + SubpelConv2xProxy() = default; + ~SubpelConv2xProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, at::Tensor& out_buf); + void release_tensors(); + void set_param(const std::map& state_dict); + +private: + at::Tensor m_weight; + at::Tensor m_weight_transposed; + at::Tensor m_bias; + + // for cuda graphs + at::Tensor m_conv_out; + at::Tensor m_shuffle_out; +}; + +class ResidualBlockWithStride2Proxy { +public: + ResidualBlockWithStride2Proxy() = default; + ~ResidualBlockWithStride2Proxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x, + const at::optional& out_buf = at::nullopt); + void release_tensors(); + void set_param(const std::map& state_dict, const bool shortcut); + +private: + at::Tensor m_weight; + at::Tensor m_bias; + DepthConvBlockProxy m_conv; + + // for cuda graphs + at::Tensor m_conv_out; +}; + +class ResidualBlockUpsampleProxy { +public: + ResidualBlockUpsampleProxy() = default; + ~ResidualBlockUpsampleProxy() = default; + + at::Tensor forward(const at::Tensor& x); + at::Tensor pre_allocate_tensors(at::Tensor& x); + void release_tensors(); + void set_param(const std::map& state_dict, const bool shortcut); + +private: + SubpelConv2xProxy m_up; + DepthConvBlockProxy m_conv; +}; diff --git a/src/layers/extensions/inference/memory_pool.cpp b/src/layers/extensions/inference/memory_pool.cpp new file mode 100644 index 0000000..8b5fe4d --- /dev/null +++ b/src/layers/extensions/inference/memory_pool.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "memory_pool.h" + +TensorPool g_tensor_pool; diff --git a/src/layers/extensions/inference/memory_pool.h b/src/layers/extensions/inference/memory_pool.h new file mode 100644 index 0000000..9d8c480 --- /dev/null +++ b/src/layers/extensions/inference/memory_pool.h @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +struct TensorEntry { + at::Tensor tensor; + c10::SmallVector sizes; + c10::Device device{ at::kCUDA, 0 }; + at::ScalarType dtype{ at::kFloat }; + c10::Layout layout{ c10::kStrided }; + bool is_channel_last{ true }; + bool reusable{ false }; +}; + +inline bool sizes_equal(c10::IntArrayRef a, c10::IntArrayRef b) +{ + if (a.size() != b.size()) return false; + for (size_t i = 0; i < a.size(); ++i) + if (a[i] != b[i]) return false; + return true; +} + +class TensorPool { +public: + TensorPool() = default; + + at::Tensor acquire(c10::IntArrayRef sizes, const at::TensorOptions& options) + { + std::lock_guard g(mu_); + const c10::Device device = options.device(); + const at::ScalarType dtype = c10::typeMetaToScalarType(options.dtype()); + const c10::Layout layout = options.layout(); + const std::optional mem_format = options.memory_format_opt(); + bool is_channel_last = + mem_format.has_value() && mem_format.value() == at::MemoryFormat::ChannelsLast; + + for (auto& e : entries_) { + if (!e.reusable) { + continue; + } + if (e.device != device || e.dtype != dtype || e.layout != layout + || e.is_channel_last != is_channel_last) { + continue; + } + if (!sizes_equal(e.sizes, sizes)) { + continue; + } + + e.reusable = false; + return e.tensor; + } + + auto t = at::empty(sizes, options); + + TensorEntry e; + e.tensor = t; + e.sizes.assign(sizes.begin(), sizes.end()); + e.device = device; + e.dtype = dtype; + e.layout = layout; + e.is_channel_last = is_channel_last; + e.reusable = false; + entries_.emplace_back(std::move(e)); + return entries_.back().tensor; + } + + void clear(int H, int W) + { + std::lock_guard g(mu_); + if (H == m_H && W == m_W) { + return; + } + entries_.clear(); + m_H = H; + m_W = W; + } + + at::Tensor empty(c10::IntArrayRef sizes, const at::TensorOptions& options) + { + return acquire(sizes, options); + } + + at::Tensor empty_like(const at::Tensor& a) + { + return acquire(a.sizes(), a.options().memory_format(a.is_contiguous(at::MemoryFormat::ChannelsLast) + ? at::MemoryFormat::ChannelsLast + : at::MemoryFormat::Contiguous)); + } + + bool release(const at::Tensor& t) + { + if (!t.defined()) { + return false; + } + return set_reusable(t, true); + } + + bool set_reusable(const at::Tensor& t, bool flag = true) + { + std::lock_guard g(mu_); + auto* impl = t.unsafeGetTensorImpl(); + for (auto& e : entries_) { + if (e.tensor.unsafeGetTensorImpl() == impl) { + e.reusable = flag; + return true; + } + } + return false; + } + +private: + mutable std::mutex mu_; + std::vector entries_; + int m_H{ 0 }; + int m_W{ 0 }; +}; + +extern TensorPool g_tensor_pool; diff --git a/src/layers/extensions/inference/pyproject.toml b/src/layers/extensions/inference/pyproject.toml new file mode 100644 index 0000000..9787c3b --- /dev/null +++ b/src/layers/extensions/inference/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/src/layers/extensions/inference/setup.py b/src/layers/extensions/inference/setup.py index 6a25fd5..3df5319 100644 --- a/src/layers/extensions/inference/setup.py +++ b/src/layers/extensions/inference/setup.py @@ -4,25 +4,77 @@ import os import glob import sys +import psutil +import torch + from setuptools import setup from torch.utils.cpp_extension import BuildExtension, CUDAExtension -cxx_flags = ["-O3"] -nvcc_flags = ["-O3", "--use_fast_math", "--extra-device-vectorization", "-arch=native"] +# Note: assume inference kernel is only built upon NVIDIA platforms. +major, minor = torch.cuda.get_device_capability(0) +sm = major * 10 + minor +if sm == 90: + arch_str = '--generate-code=arch=compute_90a,code=[sm_90a]' +elif sm == 100: + arch_str = '--generate-code=arch=compute_100a,code=[sm_100a]' +else: + arch_str = '-arch=native' + +cxx_flags = ['-O3', '-Wno-deprecated-declarations'] +# Per-nvcc internal parallelism via --split-compile=N. The inference +# extension is CUTLASS-heavy, so individual .cu translation units are +# large and benefit from intra-nvcc parallelism on top of ninja's +# cross-file parallelism. Empirically saturates around 4; pick N based +# on cpu_count so smaller hosts still leave headroom for ninja. +cpu_count = os.cpu_count() or 4 +if cpu_count < 16: + nvcc_split_compile = 1 +elif cpu_count < 32: + nvcc_split_compile = 2 +else: + nvcc_split_compile = 4 +nvcc_flags = [f'-DCURRENT_DEVICE_SM={sm}', '-O3', '--use_fast_math', + '--extra-device-vectorization', arch_str, '-Wno-deprecated-declarations', + f'--split-compile={nvcc_split_compile}'] +if sm == 90: + nvcc_flags.append('-DCUTLASS_ENABLE_GDC_FOR_SM90=1') +elif sm == 100: + nvcc_flags.append('-DCUTLASS_ENABLE_GDC_FOR_SM100=1') + if sys.platform == 'win32': - cxx_flags = ["/O2"] + cxx_flags = ['/O2'] + +cutlass_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), + '../../../../third_party/cutlass') +py_rans_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), + '../../../cpp/py_rans') +mem = psutil.virtual_memory() +mem_gb = mem.available / 1024**3 +if mem_gb < 32: + os.environ['MAX_JOBS'] = '8' +elif mem_gb < 64: + os.environ['MAX_JOBS'] = '16' setup( name='inference_extensions_cuda', ext_modules=[ CUDAExtension( name='inference_extensions_cuda', - sources=glob.glob('*.cpp') + glob.glob('*.cu'), + include_dirs=[ + os.path.join(cutlass_path, 'include'), + os.path.join(cutlass_path, 'tools', 'util', 'include'), + py_rans_path + ], + sources=( + glob.glob('**/*.cpp', recursive=True) + + glob.glob('**/*.cu', recursive=True) + + [f'{py_rans_path}/rans.cpp', f'{py_rans_path}/py_rans.cpp',] + ), extra_compile_args={ - "cxx": cxx_flags, - "nvcc": nvcc_flags, + 'cxx': cxx_flags, + 'nvcc': nvcc_flags, }, ), ], diff --git a/src/layers/layers.py b/src/layers/layers.py index a51e93d..e6521c0 100644 --- a/src/layers/layers.py +++ b/src/layers/layers.py @@ -2,155 +2,187 @@ # Licensed under the MIT License. import torch +import torch.nn.functional as F + from torch import nn -from .cuda_inference import CUSTOMIZED_CUDA_INFERENCE -if CUSTOMIZED_CUDA_INFERENCE: - from .cuda_inference import DepthConvProxy, SubpelConv2xProxy +from torch.autograd import Function +from ..utils.transforms import ycbcr2rgb -class WSiLU(nn.Module): - def __init__(self): - super().__init__() - def forward(self, x): - return torch.sigmoid(4.0 * x) * x +def bit_estimator_z_prob(x, h, b, a): + # this is accumulated prob + for i in range(4): + x = x * F.softplus(h[:, :, i:i+1, None]) + b[:, :, i:i+1, None] + if i != 3: + x = x + torch.tanh(x) * torch.tanh(a[:, :, i:i+1, None]) + return torch.sigmoid(x) -class WSiLUChunkAdd(nn.Module): - def __init__(self): - super().__init__() - self.silu = WSiLU() +def bit_estimator_z_fwd(x, h, b, a): + dtype = x.dtype + x = x.float() + h = h.float() + b = b.float() + a = a.float() + lower = bit_estimator_z_prob(x - 0.5, h, b, a) + upper = bit_estimator_z_prob(x + 0.5, h, b, a) + prob = upper - lower + return prob.to(dtype) - def forward(self, x): - x1, x2 = self.silu(x).chunk(2, 1) - return x1 + x2 + +def get_mse_yuv_rgb(x, x_hat): + mse_yuv = torch.sum(F.mse_loss(x, x_hat, reduction='none'), dim=(2, 3)) + org_rgb = ycbcr2rgb(x, clamp=False) + rec_rgb = ycbcr2rgb(x_hat, clamp=False) + mse_rgb = torch.sum(F.mse_loss(org_rgb, rec_rgb, reduction='none'), dim=(1, 2, 3)) + return mse_yuv, mse_rgb + + +def mse_8frames_sum(mse, dist_weights): + result = (mse[0] + mse[2] + mse[4] + mse[6]) * dist_weights[1] + \ + (mse[1] + mse[3] + mse[5]) * dist_weights[2] + mse[7] * dist_weights[0] + return result + + +def mse_weighted_average(mse_yuv, mse_rgb, pixel_num): + dtype = mse_yuv.dtype + mse_yuv = mse_yuv.float() + mse_rgb = mse_rgb.float() + mse_yuv = mse_yuv / pixel_num + mse_y, mse_u, mse_v = mse_yuv[:, 0], mse_yuv[:, 1], mse_yuv[:, 2] + mse_yuv = torch.exp( + 0.0833 * (10 * torch.log(torch.clamp_min(mse_y, 1e-6)) + + torch.log(torch.clamp_min(mse_u, 1e-6)) + + torch.log(torch.clamp_min(mse_v, 1e-6)))) * 3 + mse_rgb = mse_rgb / pixel_num + mse = mse_yuv * 0.8 + mse_rgb * 0.2 + return mse.to(dtype) + + +class LowerBound(Function): + @staticmethod + def forward(ctx, inputs, bound): + ctx.save_for_backward(inputs) + ctx.bound = bound + return torch.clamp_min(inputs, bound) + + @staticmethod + def backward(ctx, grad): + inputs = ctx.saved_tensors[0] + bound = ctx.bound + + pass_through_1 = inputs >= bound + pass_through_2 = grad < 0 + + pass_through = pass_through_1 | pass_through_2 + return pass_through * grad, None + + +class QuantFunc(Function): + @staticmethod + def forward(ctx, x): + return torch.round(x) + + @staticmethod + def backward(ctx, grad): + return grad class SubpelConv2x(nn.Module): - def __init__(self, in_ch, out_ch, kernel_size, padding=0): + def __init__(self, in_ch, out_ch, kernel_size, padding=0, force_bias=False): super().__init__() + has_bias = (kernel_size > 1) or force_bias self.conv = nn.Sequential( - nn.Conv2d(in_ch, out_ch * 4, kernel_size=kernel_size, padding=padding), + nn.Conv2d(in_ch, out_ch * 4, kernel_size=kernel_size, padding=padding, bias=has_bias), nn.PixelShuffle(2), ) self.padding = padding - self.proxy = None + def forward(self, x): + return self.conv(x) - def forward(self, x, to_cat=None, cat_at_front=True): - if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: - return self.forward_torch(x, to_cat, cat_at_front) - return self.forward_cuda(x, to_cat, cat_at_front) +class WSiLU(nn.Module): + def __init__(self): + super().__init__() - def forward_torch(self, x, to_cat=None, cat_at_front=True): - out = self.conv(x) - if to_cat is None: - return out - if cat_at_front: - return torch.cat((to_cat, out), dim=1) - return torch.cat((out, to_cat), dim=1) + def forward(self, x): + return torch.sigmoid(4.0 * x) * x - def forward_cuda(self, x, to_cat=None, cat_at_front=True): - if self.proxy is None: - self.proxy = SubpelConv2xProxy() - self.proxy.set_param(self.conv[0].weight, self.conv[0].bias, self.padding) - if to_cat is None: - return self.proxy.forward(x) +class WSiLUChunkAdd(nn.Module): + def __init__(self): + super().__init__() + self.wsilu = WSiLU() - return self.proxy.forward_with_cat(x, to_cat, cat_at_front) + def forward(self, x): + x = self.wsilu(x) + x1 = x[:, 0::4, :, :] + x2 = x[:, 1::4, :, :] + x3 = x[:, 2::4, :, :] + x4 = x[:, 3::4, :, :] + return x1 + x2 + x3 + x4 class DepthConvBlock(nn.Module): - def __init__(self, in_ch, out_ch, shortcut=False, force_adaptor=False): + def __init__(self, in_ch, out_ch, *, dcb2=False, shortcut=False, force_adaptor=False): super().__init__() self.adaptor = None if in_ch != out_ch or force_adaptor: self.adaptor = nn.Conv2d(in_ch, out_ch, 1) + ch_ratio = 1 + if dcb2: + assert not shortcut + ch_ratio = 2 self.shortcut = shortcut self.dc = nn.Sequential( - nn.Conv2d(out_ch, out_ch, 1), + nn.Conv2d(out_ch, out_ch // ch_ratio, 1), WSiLU(), - nn.Conv2d(out_ch, out_ch, 3, padding=1, groups=out_ch), - nn.Conv2d(out_ch, out_ch, 1), + nn.Conv2d(out_ch // ch_ratio, out_ch // ch_ratio, 3, padding=1, + groups=out_ch // ch_ratio), + nn.Conv2d(out_ch // ch_ratio, out_ch, 1), ) self.ffn = nn.Sequential( - nn.Conv2d(out_ch, out_ch * 4, 1), + nn.Conv2d(out_ch, out_ch * 4 // ch_ratio, 1), WSiLUChunkAdd(), - nn.Conv2d(out_ch * 2, out_ch, 1), + nn.Conv2d(out_ch // ch_ratio, out_ch, 1), ) - self.proxy = None - - def forward(self, x, quant_step=None, to_cat=None, cat_at_front=True): - if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: - return self.forward_torch(x, quant_step, to_cat, cat_at_front) - - return self.forward_cuda(x, quant_step, to_cat, cat_at_front) - - def forward_torch(self, x, quant_step=None, to_cat=None, cat_at_front=True): + def forward(self, x): if self.adaptor is not None: x = self.adaptor(x) out = self.dc(x) + x out = self.ffn(out) + out if self.shortcut: out = out + x - if quant_step is not None: - out = out * quant_step - if to_cat is not None: - if cat_at_front: - out = torch.cat((to_cat, out), dim=1) - else: - out = torch.cat((out, to_cat), dim=1) return out - def forward_cuda(self, x, quant_step=None, to_cat=None, cat_at_front=True): - if self.proxy is None: - self.proxy = DepthConvProxy() - if self.adaptor is not None: - self.proxy.set_param_with_adaptor(self.dc[0].weight, self.dc[0].bias, - self.dc[2].weight, self.dc[2].bias, - self.dc[3].weight, self.dc[3].bias, - self.ffn[0].weight, self.ffn[0].bias, - self.ffn[2].weight, self.ffn[2].bias, - self.adaptor.weight, self.adaptor.bias, - self.shortcut) - else: - self.proxy.set_param(self.dc[0].weight, self.dc[0].bias, - self.dc[2].weight, self.dc[2].bias, - self.dc[3].weight, self.dc[3].bias, - self.ffn[0].weight, self.ffn[0].bias, - self.ffn[2].weight, self.ffn[2].bias, - self.shortcut) - - if quant_step is not None: - return self.proxy.forward_with_quant_step(x, quant_step) - if to_cat is not None: - return self.proxy.forward_with_cat(x, to_cat, cat_at_front) - - return self.proxy.forward(x) - -class ResidualBlockWithStride2(nn.Module): - def __init__(self, in_ch, out_ch): +class ResidualBlockUpsample(nn.Module): + def __init__(self, in_ch, out_ch, dcb2=False, shortcut=True, force_bias=False): super().__init__() - self.down = nn.Conv2d(in_ch, out_ch, 2, stride=2) - self.conv = DepthConvBlock(out_ch, out_ch, shortcut=True) + self.up = SubpelConv2x(in_ch, out_ch, 1, force_bias=force_bias) + self.conv = DepthConvBlock(out_ch, out_ch, dcb2=dcb2, shortcut=shortcut) + + self.shortcut = shortcut def forward(self, x): - x = self.down(x) - out = self.conv(x) + out = self.up(x) + out = self.conv(out) return out -class ResidualBlockUpsample(nn.Module): - def __init__(self, in_ch, out_ch): +class ResidualBlockWithStride2(nn.Module): + def __init__(self, in_ch, out_ch, dcb2=False, shortcut=True): super().__init__() - self.up = SubpelConv2x(in_ch, out_ch, 1) - self.conv = DepthConvBlock(out_ch, out_ch, shortcut=True) + self.down = nn.Conv2d(in_ch * 4, out_ch, 1) + self.conv = DepthConvBlock(out_ch, out_ch, dcb2=dcb2, shortcut=shortcut) + + self.shortcut = shortcut def forward(self, x): - out = self.up(x) + out = F.pixel_unshuffle(x, 2) + out = self.down(out) out = self.conv(out) return out diff --git a/src/models/common_model.py b/src/models/common_model.py index dc18b65..aa083c4 100644 --- a/src/models/common_model.py +++ b/src/models/common_model.py @@ -1,36 +1,103 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +import math import torch +import torch.utils.checkpoint + from torch import nn -from ..layers.cuda_inference import combine_for_reading_2x, \ - restore_y_2x, restore_y_2x_with_cat_after, add_and_multiply, \ - replicate_pad, restore_y_4x, clamp_reciprocal_with_quant from .entropy_models import BitEstimator, GaussianEncoder, EntropyCoder +from ..layers.layers import LowerBound, QuantFunc, mse_weighted_average, get_mse_yuv_rgb +from ..utils.common import generate_str + + +class CkptModule(nn.Module): + def __init__(self): + super().__init__() + self.use_ckpt = False + + def internal_forward(self, *args, **kwargs): + raise NotImplementedError + + def set_use_ckpt(self, use_ckpt=True): + self.use_ckpt = use_ckpt + + def forward(self, *args, **kwargs): + if self.use_ckpt: + return torch.utils.checkpoint.checkpoint(self.internal_forward, *args, **kwargs, + preserve_rng_state=False, use_reentrant=False) + return self.internal_forward(*args, **kwargs) class CompressionModel(nn.Module): - def __init__(self, z_channel, extra_qp=0): + def __init__(self, z_channel): super().__init__() self.z_channel = z_channel self.entropy_coder = None - self.bit_estimator_z = BitEstimator(64 + extra_qp, z_channel) + self.proxy = None + self.bit_estimator_z = BitEstimator(self.qp_num(), z_channel) self.gaussian_encoder = GaussianEncoder() self.masks = {} - self.cuda_streams = {} - def get_cuda_stream(self, device, idx=0, priority=0): - key = f"{device}_{priority}_{idx}" - if key not in self.cuda_streams: - self.cuda_streams[key] = torch.cuda.Stream(device, priority=priority) - return self.cuda_streams[key] + self.prob_to_bits_factor = -1.0 / math.log(2.0) + + self.recon_range = 0.5 + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + torch.nn.init.xavier_normal_(m.weight, 1.) + if m.bias is not None: + torch.nn.init.constant_(m.bias, 0.) + + def _reset_cuda_proxies(self): + for module in self.modules(): + if hasattr(module, 'proxy'): + try: + module.proxy = None + except Exception: + pass + + def add_cdf_to_state_dict(self, state_dict): + keys = ['quantized_cdf', 'cdf_length'] + state_dict.update({'gaussian_encoder.'+key: torch.from_numpy(val) + for key, val in zip(keys, self.gaussian_encoder.get_cdf_info())}) + state_dict.update({'bit_estimator_z.'+key: torch.from_numpy(val) + for key, val in zip(keys, self.bit_estimator_z.get_cdf_info())}) + return state_dict @staticmethod - def get_qp_num(): - return 64 + def add_noise(x): + noise = torch.nn.init.uniform_(torch.empty_like(x), -0.5, 0.5) + return x + noise.detach() + + @staticmethod + def get_loss_info(rd, loss, pixel_num): + info = { + 'bpp_y': generate_str(rd['bits_y'] / pixel_num), + 'bpp_z': generate_str(rd['bits_z'] / pixel_num), + 'mse': generate_str(rd['mse']), + 'losses': generate_str(loss['losses']), + } + return info + + def get_mse(self, x, x_hat): + mse_yuv, mse_rgb = get_mse_yuv_rgb(x, x_hat) + + _, _, H, W = x.size() + pixel_num = H * W + mse = mse_weighted_average(mse_yuv, mse_rgb, pixel_num) + return mse + + @staticmethod + def get_one_mask(micro_mask, H, W): + mask = torch.tensor(micro_mask, dtype=torch.bool) + mask = mask.repeat((H + 1) // 2, (W + 1) // 2) + mask = mask[None, None, :H, :W] + return mask @staticmethod def get_padding_size(height, width, p=64): @@ -40,257 +107,176 @@ def get_padding_size(height, width, p=64): padding_bottom = new_h - height return padding_right, padding_bottom + def index_select_dim0(self, x, index): + if x is None: + return x + out = torch.index_select(x, 0, index)[:, :, None, None] + return out + + def probs_to_bits(self, probs): + dtype = probs.dtype + probs = probs.float() + bits = torch.log(LowerBound.apply(probs, 1e-6)) * self.prob_to_bits_factor + bits = LowerBound.apply(bits, 0) + return bits.to(dtype) + @staticmethod - def get_downsampled_shape(height, width, p): - new_h = (height + p - 1) // p * p - new_w = (width + p - 1) // p * p - return int(new_h / p + 0.5), int(new_w / p + 0.5) + def process_with_mask(y, scales, means, mask): + scales_hat = scales * mask + means_hat = means * mask - def update(self, force_zero_thres=None): - self.entropy_coder = EntropyCoder() - self.gaussian_encoder.update(self.entropy_coder, force_zero_thres=force_zero_thres) - self.bit_estimator_z.update(self.entropy_coder) + y_res = (y - means_hat) * mask + y_q = QuantFunc.apply(y_res) + y_hat = y_q + means_hat - def set_use_two_entropy_coders(self, use_two_entropy_coders): - self.entropy_coder.set_use_two_entropy_coders(use_two_entropy_coders) - - def pad_for_y(self, y): - _, _, H, W = y.size() - padding_r, padding_b = self.get_padding_size(H, W, 4) - y_pad = replicate_pad(y, padding_b, padding_r) - return y_pad - - def separate_prior(self, params, is_video=False): - if is_video: - quant_step, scales, means = params.chunk(3, 1) - quant_step = torch.clamp_min(quant_step, 0.5) - q_enc = 1. / quant_step - q_dec = quant_step - else: - q = params[:, :2, :, :] - q_enc, q_dec = (torch.sigmoid(q) * 1.5 + 0.5).chunk(2, 1) - scales, means = params[:, 2:, :, :].chunk(2, 1) - return q_enc, q_dec, scales, means + return y_res, y_q, y_hat, scales_hat @staticmethod - def separate_prior_for_video_encoding(params, y): - q_dec, scales, means = params.chunk(3, 1) - q_dec, y = clamp_reciprocal_with_quant(q_dec, y, 0.5) - return y, q_dec, scales, means + def qp_num(): + return 64 - @staticmethod - def separate_prior_for_video_decoding(params): + def separate_prior_image(self, params): + scales, means = params.chunk(2, 1) + return scales, means + + def separate_prior_video(self, params): quant_step, scales, means = params.chunk(3, 1) - quant_step = torch.clamp_min(quant_step, 0.5) - return quant_step, scales, means + quant_step = LowerBound.apply(quant_step, 0.5) + q_enc = 1. / quant_step + q_dec = quant_step + return q_enc, q_dec, scales, means - def process_with_mask(self, y, scales, means, mask): - return self.gaussian_encoder.process_with_mask(y, scales, means, mask) + def set_entropy_coder_parallel(self, entropy_coder_parallel): + self.entropy_coder.set_entropy_coder_parallel(entropy_coder_parallel) - @staticmethod - def get_one_mask(micro_mask, height, width, dtype, device): - mask = torch.tensor(micro_mask, dtype=dtype, device=device) - mask = mask.repeat((height + 1) // 2, (width + 1) // 2) - mask = mask[:height, :width] - mask = torch.unsqueeze(mask, 0) - mask = torch.unsqueeze(mask, 0) - return mask + def update(self, skip_thres): + self.entropy_coder = EntropyCoder() + self.gaussian_encoder.update(self.entropy_coder, skip_thres=skip_thres) + self.bit_estimator_z.update(self.entropy_coder) - def get_mask_4x(self, batch, channel, height, width, dtype, device): - curr_mask_str = f"{batch}_{channel}_{width}_{height}_4x" - with torch.no_grad(): - if curr_mask_str not in self.masks: - assert channel % 4 == 0 - m = torch.ones((batch, channel // 4, height, width), dtype=dtype, device=device) - m0 = self.get_one_mask(((1, 0), (0, 0)), height, width, dtype, device) - m1 = self.get_one_mask(((0, 1), (0, 0)), height, width, dtype, device) - m2 = self.get_one_mask(((0, 0), (1, 0)), height, width, dtype, device) - m3 = self.get_one_mask(((0, 0), (0, 1)), height, width, dtype, device) - - mask_0 = torch.cat((m * m0, m * m1, m * m2, m * m3), dim=1) - mask_1 = torch.cat((m * m3, m * m2, m * m1, m * m0), dim=1) - mask_2 = torch.cat((m * m2, m * m3, m * m0, m * m1), dim=1) - mask_3 = torch.cat((m * m1, m * m0, m * m3, m * m2), dim=1) - - self.masks[curr_mask_str] = [mask_0, mask_1, mask_2, mask_3] + @torch.no_grad() + def get_mask_2x(self, B, C, H, W, device): + curr_mask_str = f'{B}_{C}_{H}_{W}_2x' + if curr_mask_str not in self.masks: + assert C % 2 == 0 + m = torch.ones((B, C // 2, H, W), dtype=torch.bool) + m0 = self.get_one_mask(((1, 0), (0, 1)), H, W) + m1 = self.get_one_mask(((0, 1), (1, 0)), H, W) + + mask_0 = torch.cat((m * m0, m * m1), dim=1) + mask_0 = mask_0.to(device=device) + mask_1 = torch.cat((m * m1, m * m0), dim=1) + mask_1 = mask_1.to(device=device) + + self.masks[curr_mask_str] = [mask_0, mask_1] return self.masks[curr_mask_str] - def get_mask_2x(self, batch, channel, height, width, dtype, device): - curr_mask_str = f"{batch}_{channel}_{width}_{height}_2x" - with torch.no_grad(): - if curr_mask_str not in self.masks: - assert channel % 2 == 0 - m = torch.ones((batch, channel // 2, height, width), dtype=dtype, device=device) - m0 = self.get_one_mask(((1, 0), (0, 1)), height, width, dtype, device) - m1 = self.get_one_mask(((0, 1), (1, 0)), height, width, dtype, device) + @torch.no_grad() + def get_mask_4x(self, B, C, H, W, device): + curr_mask_str = f'{B}_{C}_{H}_{W}_4x' + if curr_mask_str not in self.masks: + assert C % 4 == 0 + m = torch.ones((B, C // 4, H, W), dtype=torch.bool) + m0 = self.get_one_mask(((1, 0), (0, 0)), H, W) + m1 = self.get_one_mask(((0, 1), (0, 0)), H, W) + m2 = self.get_one_mask(((0, 0), (1, 0)), H, W) + m3 = self.get_one_mask(((0, 0), (0, 1)), H, W) + + mask_0 = torch.cat((m * m0, m * m1, m * m2, m * m3), dim=1) + mask_0 = mask_0.to(device=device) + mask_1 = torch.cat((m * m3, m * m2, m * m1, m * m0), dim=1) + mask_1 = mask_1.to(device=device) + mask_2 = torch.cat((m * m2, m * m3, m * m0, m * m1), dim=1) + mask_2 = mask_2.to(device=device) + mask_3 = torch.cat((m * m1, m * m0, m * m3, m * m2), dim=1) + mask_3 = mask_3.to(device=device) + + self.masks[curr_mask_str] = [mask_0, mask_1, mask_2, mask_3] + return self.masks[curr_mask_str] - mask_0 = torch.cat((m * m0, m * m1), dim=1) - mask_1 = torch.cat((m * m1, m * m0), dim=1) + def get_y_bits(self, y, sigma): + probs = self.gaussian_encoder.get_prob_train(y, sigma) + return self.probs_to_bits(probs) - self.masks[curr_mask_str] = [mask_0, mask_1] - return self.masks[curr_mask_str] + def get_z_bits(self, z, index): + probs = self.bit_estimator_z.get_prob(z, index) + return self.probs_to_bits(probs) - @staticmethod - def single_part_for_writing_4x(x): - x0, x1, x2, x3 = x.chunk(4, 1) - return (x0 + x1) + (x2 + x3) + def load_state_dict(self, state_dict, *args, **kwargs): + res = super().load_state_dict(state_dict, *args, **kwargs) + # CUDA proxy params are cached via .set_param(self.state_dict()) on first use. + # When weights are reloaded, proxies must be reset to avoid using stale params. + self._reset_cuda_proxies() + return res - @staticmethod - def single_part_for_writing_2x(x): - x0, x1 = x.chunk(2, 1) - return x0 + x1 - - def compress_prior_2x(self, y, common_params, y_spatial_prior): - y, q_dec, scales, means = self.separate_prior_for_video_encoding(common_params, y) - dtype = y.dtype - device = y.device + def forward_prior_2x(self, y, common_params, y_spatial_prior): + q_enc, q_dec, scales, means = self.separate_prior_video(common_params) + y = y * q_enc + device = common_params.device B, C, H, W = y.size() - mask_0, mask_1 = self.get_mask_2x(B, C, H, W, dtype, device) - - _, y_q_0, y_hat_0, s_hat_0 = self.process_with_mask(y, scales, means, mask_0) - cat_params = torch.cat((y_hat_0, common_params), dim=1) - scales, means = y_spatial_prior(cat_params).chunk(2, 1) - _, y_q_1, y_hat_1, s_hat_1 = self.process_with_mask(y, scales, means, mask_1) - - y_hat = add_and_multiply(y_hat_0, y_hat_1, q_dec) - - y_q_w_0 = self.single_part_for_writing_2x(y_q_0) - y_q_w_1 = self.single_part_for_writing_2x(y_q_1) - s_w_0 = self.single_part_for_writing_2x(s_hat_0) - s_w_1 = self.single_part_for_writing_2x(s_hat_1) - return y_q_w_0, y_q_w_1, s_w_0, s_w_1, y_hat - - def decompress_prior_2x(self, common_params, y_spatial_prior): - infos = self.decompress_prior_2x_part1(common_params) - y_hat = self.decompress_prior_2x_part2(common_params, y_spatial_prior, infos) - return y_hat - - def decompress_prior_2x_part1(self, common_params): - q_dec, scales, means = self.separate_prior_for_video_decoding(common_params) - dtype = means.dtype - device = means.device - B, C, H, W = means.size() - mask_0, mask_1 = self.get_mask_2x(B, C, H, W, dtype, device) - - scales_r = combine_for_reading_2x(scales, mask_0, inplace=False) - indexes, skip_cond = self.gaussian_encoder.build_indexes_decoder(scales_r) - self.gaussian_encoder.decode_y(indexes) - infos = { - "q_dec": q_dec, - "mask_0": mask_0, - "mask_1": mask_1, - "means": means, - "scales_r": scales_r, - "skip_cond": skip_cond, - "indexes": indexes, - } - return infos + mask_0, mask_1 = self.get_mask_2x(B, C, H, W, device) + + y_res_0, y_q_0, y_hat_0, s_hat_0 = self.process_with_mask(y, scales, means, mask_0) + means = y_spatial_prior(y_hat_0, common_params) + y_res_1, y_q_1, y_hat_1, s_hat_1 = self.process_with_mask(y, scales, means, mask_1) + + y_hat = y_hat_0 + y_hat_1 + y_hat = y_hat * q_dec + + y_res = None if y_res_0 is None else y_res_0 + y_res_1 + y_q = None if y_q_0 is None else y_q_0 + y_q_1 + scales_hat = s_hat_0 + s_hat_1 + return y_res, y_q, y_hat, scales_hat + + def forward_prior_4x(self, y, q_enc, q_dec, + common_params, y_spatial_prior_reduction, + y_spatial_prior_adaptor_1, y_spatial_prior_adaptor_2, + y_spatial_prior_adaptor_3, y_spatial_prior, + spatial_prior_has_scales=False): + if q_enc is None: + q_enc, q_dec, scales, means = self.separate_prior_video(common_params) + y = y * q_enc + else: + spatial_prior_has_scales = True + scales, means = self.separate_prior_image(common_params) + y = y * q_enc - def decompress_prior_2x_part2(self, common_params, y_spatial_prior, infos): - dtype = common_params.dtype - device = common_params.device - y_q_r = self.gaussian_encoder.get_y(infos["scales_r"].shape, - infos["scales_r"].numel(), - dtype, device, - infos["skip_cond"], infos["indexes"]) - y_hat_0, cat_params = restore_y_2x_with_cat_after(y_q_r, infos["means"], infos["mask_0"], - common_params) - scales, means = y_spatial_prior(cat_params).chunk(2, 1) - scales_r = combine_for_reading_2x(scales, infos["mask_1"], inplace=True) - y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) - y_hat_1 = restore_y_2x(y_q_r, means, infos["mask_1"]) - - y_hat = add_and_multiply(y_hat_0, y_hat_1, infos["q_dec"]) - return y_hat - - def compress_prior_4x(self, y, common_params, y_spatial_prior_reduction, - y_spatial_prior_adaptor_1, y_spatial_prior_adaptor_2, - y_spatial_prior_adaptor_3, y_spatial_prior): - ''' - y_0 means split in channel, the 0/4 quater - y_1 means split in channel, the 1/4 quater - y_2 means split in channel, the 2/4 quater - y_3 means split in channel, the 3/4 quater - y_?_0, means multiply with mask_0 - y_?_1, means multiply with mask_1 - y_?_2, means multiply with mask_2 - y_?_3, means multiply with mask_3 - ''' - q_enc, q_dec, scales, means = self.separate_prior(common_params, False) common_params = y_spatial_prior_reduction(common_params) - dtype = y.dtype - device = y.device + device = common_params.device B, C, H, W = y.size() - mask_0, mask_1, mask_2, mask_3 = self.get_mask_4x(B, C, H, W, dtype, device) + mask_0, mask_1, mask_2, mask_3 = self.get_mask_4x(B, C, H, W, device) - y = y * q_enc - - _, y_q_0, y_hat_0, s_hat_0 = self.process_with_mask(y, scales, means, mask_0) + y_res_0, y_q_0, y_hat_0, s_hat_0 = self.process_with_mask(y, scales, means, mask_0) y_hat_so_far = y_hat_0 - params = torch.cat((y_hat_so_far, common_params), dim=1) - scales, means = y_spatial_prior(y_spatial_prior_adaptor_1(params)).chunk(2, 1) - _, y_q_1, y_hat_1, s_hat_1 = self.process_with_mask(y, scales, means, mask_1) + if spatial_prior_has_scales: + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_1(params)).chunk(2, 1) + else: + means = y_spatial_prior(y_spatial_prior_adaptor_1(y_hat_so_far, common_params)) + y_res_1, y_q_1, y_hat_1, s_hat_1 = self.process_with_mask(y, scales, means, mask_1) y_hat_so_far = y_hat_so_far + y_hat_1 - params = torch.cat((y_hat_so_far, common_params), dim=1) - scales, means = y_spatial_prior(y_spatial_prior_adaptor_2(params)).chunk(2, 1) - _, y_q_2, y_hat_2, s_hat_2 = self.process_with_mask(y, scales, means, mask_2) + if spatial_prior_has_scales: + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_2(params)).chunk(2, 1) + else: + means = y_spatial_prior(y_spatial_prior_adaptor_2(y_hat_so_far, common_params)) + y_res_2, y_q_2, y_hat_2, s_hat_2 = self.process_with_mask(y, scales, means, mask_2) y_hat_so_far = y_hat_so_far + y_hat_2 - params = torch.cat((y_hat_so_far, common_params), dim=1) - scales, means = y_spatial_prior(y_spatial_prior_adaptor_3(params)).chunk(2, 1) - _, y_q_3, y_hat_3, s_hat_3 = self.process_with_mask(y, scales, means, mask_3) + if spatial_prior_has_scales: + params = torch.cat((y_hat_so_far, common_params), dim=1) + scales, means = y_spatial_prior(y_spatial_prior_adaptor_3(params)).chunk(2, 1) + else: + means = y_spatial_prior(y_spatial_prior_adaptor_3(y_hat_so_far, common_params)) + y_res_3, y_q_3, y_hat_3, s_hat_3 = self.process_with_mask(y, scales, means, mask_3) y_hat = y_hat_so_far + y_hat_3 y_hat = y_hat * q_dec - y_q_w_0 = self.single_part_for_writing_4x(y_q_0) - y_q_w_1 = self.single_part_for_writing_4x(y_q_1) - y_q_w_2 = self.single_part_for_writing_4x(y_q_2) - y_q_w_3 = self.single_part_for_writing_4x(y_q_3) - s_w_0 = self.single_part_for_writing_4x(s_hat_0) - s_w_1 = self.single_part_for_writing_4x(s_hat_1) - s_w_2 = self.single_part_for_writing_4x(s_hat_2) - s_w_3 = self.single_part_for_writing_4x(s_hat_3) - return y_q_w_0, y_q_w_1, y_q_w_2, y_q_w_3, s_w_0, s_w_1, s_w_2, s_w_3, y_hat - - def decompress_prior_4x(self, common_params, y_spatial_prior_reduction, - y_spatial_prior_adaptor_1, y_spatial_prior_adaptor_2, - y_spatial_prior_adaptor_3, y_spatial_prior): - _, quant_step, scales, means = self.separate_prior(common_params, False) - common_params = y_spatial_prior_reduction(common_params) - dtype = means.dtype - device = means.device - B, C, H, W = means.size() - mask_0, mask_1, mask_2, mask_3 = self.get_mask_4x(B, C, H, W, dtype, device) - - scales_r = self.single_part_for_writing_4x(scales * mask_0) - y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) - y_hat_curr_step = restore_y_4x(y_q_r, means, mask_0) - y_hat_so_far = y_hat_curr_step - - params = torch.cat((y_hat_so_far, common_params), dim=1) - scales, means = y_spatial_prior(y_spatial_prior_adaptor_1(params)).chunk(2, 1) - scales_r = self.single_part_for_writing_4x(scales * mask_1) - y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) - y_hat_curr_step = restore_y_4x(y_q_r, means, mask_1) - y_hat_so_far = y_hat_so_far + y_hat_curr_step - - params = torch.cat((y_hat_so_far, common_params), dim=1) - scales, means = y_spatial_prior(y_spatial_prior_adaptor_2(params)).chunk(2, 1) - scales_r = self.single_part_for_writing_4x(scales * mask_2) - y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) - y_hat_curr_step = restore_y_4x(y_q_r, means, mask_2) - y_hat_so_far = y_hat_so_far + y_hat_curr_step - - params = torch.cat((y_hat_so_far, common_params), dim=1) - scales, means = y_spatial_prior(y_spatial_prior_adaptor_3(params)).chunk(2, 1) - scales_r = self.single_part_for_writing_4x(scales * mask_3) - y_q_r = self.gaussian_encoder.decode_and_get_y(scales_r, dtype, device) - y_hat_curr_step = restore_y_4x(y_q_r, means, mask_3) - y_hat_so_far = y_hat_so_far + y_hat_curr_step - - y_hat = y_hat_so_far * quant_step - - return y_hat + y_res = None if y_res_0 is None else (y_res_0 + y_res_1) + (y_res_2 + y_res_3) + y_q = None if y_q_0 is None else (y_q_0 + y_q_1) + (y_q_2 + y_q_3) + scales_hat = (s_hat_0 + s_hat_1) + (s_hat_2 + s_hat_3) + + return y_res, y_q, y_hat, scales_hat diff --git a/src/models/entropy_models.py b/src/models/entropy_models.py index 9b64d28..4db9eb3 100644 --- a/src/models/entropy_models.py +++ b/src/models/entropy_models.py @@ -1,11 +1,30 @@ -import math +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +import math import torch -import numpy as np + from torch import nn -import torch.nn.functional as F -from ..layers.cuda_inference import build_index_dec, build_index_enc, process_with_mask +from ..layers.layers import bit_estimator_z_fwd, bit_estimator_z_prob, LowerBound + + +MAX_ENTROPY_CODING_VALUE = 8 + + +class AEHelper(): + def __init__(self): + super().__init__() + self.entropy_coder = None + self._quantized_cdf = None + self._cdf_length = None + + def get_cdf_info(self): + return self._quantized_cdf, self._cdf_length + + def set_cdf_info(self, quantized_cdf, cdf_length): + self._quantized_cdf = quantized_cdf.cpu().numpy() + self._cdf_length = cdf_length.reshape(-1).int().cpu().numpy() class EntropyCoder(): @@ -17,257 +36,173 @@ def __init__(self): self.decoder = RansDecoder() @staticmethod - def pmf_to_quantized_cdf(pmf, precision=16): + def pmf_to_quantized_cdf(pmf): from MLCodec_extensions_cpp import pmf_to_quantized_cdf as _pmf_to_cdf - cdf = _pmf_to_cdf(pmf.tolist(), precision) + cdf = _pmf_to_cdf(pmf.tolist()) cdf = torch.IntTensor(cdf) return cdf + @staticmethod + def reorder_prob(prob): + # prob is with length l, with the last one tail_prob + # the first (l-1) probs are sysmmetric about 0, in increasing order + # we want to make the first a few probs in 0, 1, -1, 2, -2, ... order + length = prob.size(0) + prob1 = prob.clone() + center = (length - 1) // 2 + prob1[0] = prob[center] + for i in range(1, center + 1): + prob1[2 * i - 1] = prob[center + i] + prob1[2 * i - 0] = prob[center - i] + return prob1 + + def set_cdf(self, cdf, cdf_length, index): + self.encoder.set_cdf(cdf, cdf_length, index) + self.decoder.set_cdf(cdf, cdf_length, index) + + def set_entropy_coder_parallel(self, entropy_coder_parallel): + self.encoder.set_entropy_coder_parallel(entropy_coder_parallel) + self.decoder.set_entropy_coder_parallel(entropy_coder_parallel) + @staticmethod def pmf_to_cdf(pmf, tail_mass, pmf_length, max_length): - entropy_coder_precision = 16 cdf = torch.zeros((len(pmf_length), max_length + 2), dtype=torch.int32) for i, p in enumerate(pmf): prob = torch.cat((p[: pmf_length[i]], tail_mass[i]), dim=0) - _cdf = EntropyCoder.pmf_to_quantized_cdf(prob, entropy_coder_precision) + prob1 = EntropyCoder.reorder_prob(prob) + _cdf = EntropyCoder.pmf_to_quantized_cdf(prob1) cdf[i, : _cdf.size(0)] = _cdf return cdf - def reset(self): - self.encoder.reset() - - def add_cdf(self, cdf, cdf_length, offset): - enc_cdf_idx = self.encoder.add_cdf(cdf, cdf_length, offset) - dec_cdf_idx = self.decoder.add_cdf(cdf, cdf_length, offset) - assert enc_cdf_idx == dec_cdf_idx - return enc_cdf_idx - - def encode_y(self, symbols, cdf_group_index): - # symbols: int16, high 8 bits: int8 symbol to be encoded; low 8 bits: uint8 index to use - assert symbols.dtype == torch.int16 - self.encoder.encode_y(symbols.cpu().numpy(), cdf_group_index) - - def encode_z(self, symbols, cdf_group_index, start_offset, per_channel_size): - self.encoder.encode_z(symbols.to(torch.int8).cpu().numpy(), - cdf_group_index, start_offset, per_channel_size) - - def flush(self): - self.encoder.flush() - - def get_encoded_stream(self): - return self.encoder.get_encoded_stream().tobytes() - - def set_stream(self, stream): - self.decoder.set_stream((np.frombuffer(stream, dtype=np.uint8))) - - def decode_y(self, indexes, cdf_group_index): - self.decoder.decode_y(indexes.to(torch.uint8).cpu().numpy(), cdf_group_index) - - def decode_and_get_y(self, indexes, cdf_group_index, device, dtype): - rv = self.decoder.decode_and_get_y(indexes.to(torch.uint8).cpu().numpy(), cdf_group_index) - rv = torch.as_tensor(rv) - return rv.to(device).to(dtype) - - def decode_z(self, total_size, cdf_group_index, start_offset, per_channel_size): - self.decoder.decode_z(total_size, cdf_group_index, start_offset, per_channel_size) - - def get_decoded_tensor(self, device, dtype, non_blocking=False): - rv = self.decoder.get_decoded_tensor() - rv = torch.as_tensor(rv) - return rv.to(device, non_blocking=non_blocking).to(dtype) - - def set_use_two_entropy_coders(self, use_two_entropy_coders): - self.encoder.set_use_two_encoders(use_two_entropy_coders) - self.decoder.set_use_two_decoders(use_two_entropy_coders) - - -class Bitparm(nn.Module): - def __init__(self, qp_num, channel, final=False): - super().__init__() - self.final = final - self.h = nn.Parameter(torch.nn.init.normal_( - torch.empty([qp_num, channel, 1, 1]), 0, 0.01)) - self.b = nn.Parameter(torch.nn.init.normal_( - torch.empty([qp_num, channel, 1, 1]), 0, 0.01)) - if not final: - self.a = nn.Parameter(torch.nn.init.normal_( - torch.empty([qp_num, channel, 1, 1]), 0, 0.01)) - else: - self.a = None - - def forward(self, x, index): - h = torch.index_select(self.h, 0, index) - b = torch.index_select(self.b, 0, index) - x = x * F.softplus(h) + b - if self.final: - return x - - a = torch.index_select(self.a, 0, index) - return x + torch.tanh(x) * torch.tanh(a) - - -class AEHelper(): - def __init__(self): - super().__init__() - self.entropy_coder = None - self.cdf_group_index = None - self._offset = None - self._quantized_cdf = None - self._cdf_length = None - - def set_cdf_info(self, quantized_cdf, cdf_length, offset): - self._quantized_cdf = quantized_cdf.cpu().numpy() - self._cdf_length = cdf_length.reshape(-1).int().cpu().numpy() - self._offset = offset.reshape(-1).int().cpu().numpy() - - def get_cdf_info(self): - return self._quantized_cdf, \ - self._cdf_length, \ - self._offset - class BitEstimator(AEHelper, nn.Module): def __init__(self, qp_num, channel): super().__init__() - self.f1 = Bitparm(qp_num, channel) - self.f2 = Bitparm(qp_num, channel) - self.f3 = Bitparm(qp_num, channel) - self.f4 = Bitparm(qp_num, channel, True) + self.layer_num = 4 + self.h = nn.Parameter( + torch.nn.init.normal_(torch.empty([qp_num, channel, self.layer_num]), 0, 0.01)) + self.b = nn.Parameter( + torch.nn.init.normal_(torch.empty([qp_num, channel, self.layer_num]), 0, 0.01)) + self.a = nn.Parameter( + torch.nn.init.normal_(torch.empty([qp_num, channel, self.layer_num - 1]), 0, 0.01)) self.qp_num = qp_num self.channel = channel - def forward(self, x, index): - return self.get_cdf(x, index) + def get_hba(self, index, dtype=None): + if isinstance(index, int): + h = self.h[index:index+1, :, :] + b = self.b[index:index+1, :, :] + a = self.a[index:index+1, :, :] + else: + h = torch.index_select(self.h, 0, index) + b = torch.index_select(self.b, 0, index) + a = torch.index_select(self.a, 0, index) + if dtype is not None: + return h.to(dtype), b.to(dtype), a.to(dtype) + return h, b, a - def get_logits_cdf(self, x, index): - x = self.f1(x, index) - x = self.f2(x, index) - x = self.f3(x, index) - x = self.f4(x, index) - return x + def forward(self, x, index): + h, b, a = self.get_hba(index) + return bit_estimator_z_prob(x, h, b, a) - def get_cdf(self, x, index): - return torch.sigmoid(self.get_logits_cdf(x, index)) + def get_prob(self, x, index): + h, b, a = self.get_hba(index, dtype=x.dtype) + prob = bit_estimator_z_fwd(x, h, b, a) + return prob + @torch.inference_mode() def update(self, entropy_coder): self.entropy_coder = entropy_coder - with torch.no_grad(): - device = next(self.parameters()).device - medians = torch.zeros((self.qp_num, self.channel, 1, 1), device=device) - index = torch.arange(self.qp_num, device=device, dtype=torch.int32) - - minima = medians + 8 - for i in range(8, 1, -1): - samples = torch.zeros_like(medians) - i - probs = self.forward(samples, index) - minima = torch.where(probs < torch.zeros_like(medians) + 0.0001, - torch.zeros_like(medians) + i, minima) - - maxima = medians + 8 - for i in range(8, 1, -1): - samples = torch.zeros_like(medians) + i - probs = self.forward(samples, index) - maxima = torch.where(probs > torch.zeros_like(medians) + 0.9999, - torch.zeros_like(medians) + i, maxima) - - minima = minima.int() - maxima = maxima.int() - - offset = -minima - - pmf_start = medians - minima - pmf_length = maxima + minima + 1 + device = next(self.parameters()).device + zeros = torch.zeros((self.qp_num, self.channel, 1, 1), device=device) + index = torch.arange(self.qp_num, device=device, dtype=torch.int32) - max_length = pmf_length.max() - device = pmf_start.device - samples = torch.arange(max_length, device=device) + sym_range = zeros + MAX_ENTROPY_CODING_VALUE + for i in range(MAX_ENTROPY_CODING_VALUE, 1, -1): + neg_probs = self.forward(zeros - i, index) + pos_probs = self.forward(zeros + i, index) + sym_range = torch.where(torch.logical_and(neg_probs < 0.001, pos_probs > 0.999), + i, sym_range) - samples = samples[None, None, None, :] + pmf_start + sym_range = sym_range.int() + pmf_length = sym_range * 2 + 1 - half = float(0.5) + max_length = MAX_ENTROPY_CODING_VALUE * 2 + 1 + samples = torch.arange(max_length, device=device) + samples = samples[None, None, None, :] - sym_range - lower = self.forward(samples - half, index) - upper = self.forward(samples + half, index) - pmf = upper - lower - - pmf = pmf[:, :, 0, :] - upper = self.forward(maxima.to(torch.float32), index) - tail_mass = lower[:, :, 0, :1] + (1.0 - upper[:, :, 0, -1:]) - - pmf = pmf.reshape([-1, max_length]) - tail_mass = tail_mass.reshape([-1, 1]) - pmf_length = pmf_length.reshape([-1]) - offset = offset.reshape([-1]) - quantized_cdf = EntropyCoder.pmf_to_cdf(pmf, tail_mass, pmf_length, max_length) - cdf_length = pmf_length + 2 - self.set_cdf_info(quantized_cdf, cdf_length, offset) - self.cdf_group_index = self.entropy_coder.add_cdf(*self.get_cdf_info()) - - def build_indexes(self, size, qp): - B, C, H, W = size - indexes = torch.arange(C, dtype=torch.int).view(1, -1, 1, 1) + qp * self.channel - return indexes.repeat(B, 1, H, W) - - def encode_z(self, x, qp): - _, _, H, W = x.size() - return self.entropy_coder.encode_z(x.reshape(-1), self.cdf_group_index, qp * self.channel, - H * W) + lower = self.forward(samples - 0.5, index) + upper = self.forward(samples + 0.5, index) + pmf = upper - lower - def decode_z(self, size, qp): - self.entropy_coder.decode_z(self.channel * size[0] * size[1], self.cdf_group_index, - qp * self.channel, size[0] * size[1]) + pmf = pmf[:, :, 0, :] + upper = self.forward(sym_range.float(), index) + tail_mass = lower[:, :, 0, :1] + (1.0 - upper[:, :, 0, -1:]) - def get_z(self, size, device, dtype): - output_size = (1, self.channel, size[0], size[1]) - val = self.entropy_coder.get_decoded_tensor(device, dtype, non_blocking=True) - return val.reshape(output_size) + pmf = pmf.reshape([-1, max_length]) + tail_mass = tail_mass.reshape([-1, 1]) + pmf_length = pmf_length.reshape([-1]) + quantized_cdf = EntropyCoder.pmf_to_cdf(pmf, tail_mass, pmf_length, max_length) + cdf_length = pmf_length + 2 + self.set_cdf_info(quantized_cdf, cdf_length) + self.entropy_coder.set_cdf(*self.get_cdf_info(), 0) -class GaussianEncoder(AEHelper): +class GaussianEncoder(AEHelper, nn.Module): def __init__(self): super().__init__() self.scale_min = 0.11 self.scale_max = 16.0 - self.scale_level = 128 # <= 256 - self.scale_table = self.get_scale_table(self.scale_min, self.scale_max, self.scale_level) + self.scale_level = 128 + self.scale_table = self.get_scale_table() - self.log_scale_min = math.log(self.scale_min) - self.log_scale_max = math.log(self.scale_max) - self.log_scale_step = (self.log_scale_max - self.log_scale_min) / (self.scale_level - 1) - self.log_step_recip = 1. / self.log_scale_step - - self.force_zero_thres = None - self.decode_index_cache = {} - self.decode_zeros_cache = {} + self.skip_thres = 0 @staticmethod - def get_scale_table(min_val, max_val, levels): - return torch.exp(torch.linspace(math.log(min_val), math.log(max_val), levels)) - - def update(self, entropy_coder, force_zero_thres=None): + def get_prob_train(values, scales): + def _cdf2(inputs): + const = float(-(2 ** -0.5)) + return torch.erfc(const * inputs) + + dtype = values.dtype + values = values.float() + scales = scales.float() + scales = LowerBound.apply(scales, 0.11) + values = torch.abs(values) + upper = _cdf2((0.5 - values) / scales) + lower = _cdf2((-0.5 - values) / scales) + prob = upper - lower + prob = torch.clamp_min(0.5 * prob, 1e-9) + return prob.to(dtype) + + def get_scale_table(self): + return torch.exp(torch.linspace(math.log(self.scale_min), + math.log(self.scale_max), + self.scale_level)) + + def update(self, entropy_coder, skip_thres): self.entropy_coder = entropy_coder - self.force_zero_thres = force_zero_thres + self.skip_thres = skip_thres - pmf_center = torch.zeros_like(self.scale_table) + 8 - scales = torch.zeros_like(pmf_center) + self.scale_table + zeros = torch.zeros_like(self.scale_table) + sym_range = zeros + MAX_ENTROPY_CODING_VALUE + scales = self.scale_table cdf_distribution = torch.distributions.normal.Normal(0., scales) - for i in range(8, 1, -1): - samples = torch.zeros_like(pmf_center) + i + for i in range(MAX_ENTROPY_CODING_VALUE, 1, -1): + samples = zeros + i probs = cdf_distribution.cdf(samples) probs = torch.squeeze(probs) - pmf_center = torch.where(probs > torch.zeros_like(pmf_center) + 0.9999, - torch.zeros_like(pmf_center) + i, pmf_center) + sym_range = torch.where(probs > 0.999, i, sym_range) - pmf_center = pmf_center.int() - pmf_length = 2 * pmf_center + 1 - max_length = torch.max(pmf_length).item() + sym_range = sym_range.int() + pmf_length = 2 * sym_range + 1 + max_length = 2 * MAX_ENTROPY_CODING_VALUE + 1 - device = pmf_center.device - samples = torch.arange(max_length, device=device) - pmf_center[:, None] + samples = torch.arange(max_length, device=sym_range.device) - sym_range[:, None] samples = samples.float() - scales = torch.zeros_like(samples) + self.scale_table[:, None] + scales = self.scale_table[:, None] cdf_distribution = torch.distributions.normal.Normal(0., scales) upper = cdf_distribution.cdf(samples + 0.5) @@ -276,66 +211,7 @@ def update(self, entropy_coder, force_zero_thres=None): tail_mass = 2 * lower[:, :1] - quantized_cdf = torch.Tensor(len(pmf_length), max_length + 2) quantized_cdf = EntropyCoder.pmf_to_cdf(pmf, tail_mass, pmf_length, max_length) - self.set_cdf_info(quantized_cdf, pmf_length+2, -pmf_center) - self.cdf_group_index = self.entropy_coder.add_cdf(*self.get_cdf_info()) - - def process_with_mask(self, y, scales, means, mask): - return process_with_mask(y, scales, means, mask, self.force_zero_thres) - - def build_indexes_decoder(self, scales): - scales = scales.reshape(-1) - indexes, skip_cond = build_index_dec(scales, self.scale_min, self.scale_max, - self.log_scale_min, self.log_step_recip, - self.force_zero_thres) - if self.force_zero_thres is not None: - indexes = indexes[skip_cond] - return indexes, skip_cond - - def build_indexes_encoder(self, symbols, scales): - symbols = symbols.reshape(-1) - scales = scales.reshape(-1) - symbols = build_index_enc(symbols, scales, self.scale_min, self.scale_max, - self.log_scale_min, self.log_step_recip, self.force_zero_thres) - return symbols - - def encode_y(self, x, scales): - symbols = self.build_indexes_encoder(x, scales) - return self.entropy_coder.encode_y(symbols, self.cdf_group_index) - - def get_decode_index_cache(self, num, device): - if num not in self.decode_index_cache: - c = torch.arange(0, num, dtype=torch.int32, device=device) - self.decode_index_cache[num] = c - - return self.decode_index_cache[num] - - def get_decode_zeros_cache(self, num, device): - if num not in self.decode_zeros_cache: - c = torch.zeros(num, dtype=torch.int32, device=device) - self.decode_zeros_cache[num] = c - - return self.decode_zeros_cache[num].clone() - - def decode_and_get_y(self, scales, dtype, device): - indexes, skip_cond = self.build_indexes_decoder(scales) - self.decode_y(indexes) - return self.get_y(scales.shape, scales.numel(), dtype, device, skip_cond, indexes) - - def decode_y(self, indexes): - self.entropy_coder.decode_y(indexes, self.cdf_group_index) - - def get_y(self, shape, numel, dtype, device, skip_cond, indexes): - if len(indexes) == 0: - return torch.zeros(shape, dtype=dtype, device=device) - if skip_cond is not None: - curr_index = self.get_decode_index_cache(numel, device) - back_index = self.get_decode_zeros_cache(numel, device) - back_index.masked_scatter_(skip_cond, curr_index) - val = self.entropy_coder.get_decoded_tensor(device, dtype, non_blocking=True) - if skip_cond is not None: - y = torch.index_select(val, 0, back_index) * skip_cond - return y.reshape(shape) - return val.reshape(shape) + self.set_cdf_info(quantized_cdf, pmf_length+2) + self.entropy_coder.set_cdf(*self.get_cdf_info(), 1) diff --git a/src/models/image_model.py b/src/models/image_model.py index fa1ea67..8310924 100644 --- a/src/models/image_model.py +++ b/src/models/image_model.py @@ -1,57 +1,29 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +import numpy as np import torch -from torch import nn import torch.nn.functional as F +from torch import nn from .common_model import CompressionModel -from ..layers.layers import DepthConvBlock, ResidualBlockUpsample, ResidualBlockWithStride2 -from ..layers.cuda_inference import CUSTOMIZED_CUDA_INFERENCE, round_and_to_int8 - -g_ch_src = 3 * 8 * 8 -g_ch_enc_dec = 368 - - -class IntraEncoder(nn.Module): - def __init__(self, N): - super().__init__() - - self.enc_1 = DepthConvBlock(g_ch_src, g_ch_enc_dec) - self.enc_2 = nn.Sequential( - DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), - DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), - DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), - DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), - DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), - DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), - nn.Conv2d(g_ch_enc_dec, N, 3, stride=2, padding=1), - ) +from ..layers.layers import DepthConvBlock, QuantFunc, ResidualBlockUpsample, ResidualBlockWithStride2 +from ..utils.common import loss_func - def forward(self, x, quant_step): - out = F.pixel_unshuffle(x, 8) - if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: - return self.forward_torch(out, quant_step) - - return self.forward_cuda(out, quant_step) - def forward_torch(self, out, quant_step): - out = self.enc_1(out) - out = out * quant_step - return self.enc_2(out) - - def forward_cuda(self, out, quant_step): - out = self.enc_1(out, quant_step=quant_step) - return self.enc_2(out) +g_ch_src = 3 * 8 * 8 +g_ch_enc_dec = 384 +g_ch_y = 256 +g_ch_z = 128 class IntraDecoder(nn.Module): - def __init__(self, N): + def __init__(self): super().__init__() self.dec_1 = nn.Sequential( - ResidualBlockUpsample(N, g_ch_enc_dec), + ResidualBlockUpsample(g_ch_y, g_ch_enc_dec), DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), @@ -68,142 +40,188 @@ def __init__(self, N): self.dec_2 = DepthConvBlock(g_ch_enc_dec, g_ch_src) def forward(self, x, quant_step): - if not CUSTOMIZED_CUDA_INFERENCE or not x.is_cuda: - return self.forward_torch(x, quant_step) - - return self.forward_cuda(x, quant_step) - - def forward_torch(self, x, quant_step): out = self.dec_1(x) out = out * quant_step out = self.dec_2(out) out = F.pixel_shuffle(out, 8) return out - def forward_cuda(self, x, quant_step): - out = self.dec_1[0](x) - out = self.dec_1[1](out) - out = self.dec_1[2](out) - out = self.dec_1[3](out) - out = self.dec_1[4](out) - out = self.dec_1[5](out) - out = self.dec_1[6](out) - out = self.dec_1[7](out) - out = self.dec_1[8](out) - out = self.dec_1[9](out) - out = self.dec_1[10](out) - out = self.dec_1[11](out) - out = self.dec_1[12](out, quant_step=quant_step) - out = self.dec_2(out) - out = F.pixel_shuffle(out, 8) - return out +class IntraEncoder(nn.Module): + def __init__(self): + super().__init__() -class DMCI(CompressionModel): - def __init__(self, N=256, z_channel=128): - super().__init__(z_channel=z_channel) + self.enc_1 = DepthConvBlock(g_ch_src, g_ch_enc_dec) + self.enc_2 = nn.Sequential( + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + DepthConvBlock(g_ch_enc_dec, g_ch_enc_dec), + nn.Conv2d(g_ch_enc_dec, g_ch_y, 3, stride=2, padding=1), + ) + + def forward(self, x, quant_step): + out = F.pixel_unshuffle(x, 8) + out = self.enc_1(out) + out = out * quant_step + return self.enc_2(out) - self.enc = IntraEncoder(N) - self.hyper_enc = nn.Sequential( - DepthConvBlock(N, z_channel), - ResidualBlockWithStride2(z_channel, z_channel), - ResidualBlockWithStride2(z_channel, z_channel), +class IntraHyperDecoder(nn.Module): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + ResidualBlockUpsample(g_ch_z, g_ch_z), + ResidualBlockUpsample(g_ch_z, g_ch_z), + DepthConvBlock(g_ch_z, g_ch_y), ) - self.hyper_dec = nn.Sequential( - ResidualBlockUpsample(z_channel, z_channel), - ResidualBlockUpsample(z_channel, z_channel), - DepthConvBlock(z_channel, N), + def forward(self, x): + return self.conv(x) + + +class IntraHyperEncoder(nn.Module): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y, g_ch_z), + ResidualBlockWithStride2(g_ch_z, g_ch_z), + ResidualBlockWithStride2(g_ch_z, g_ch_z), ) - self.y_prior_fusion = nn.Sequential( - DepthConvBlock(N, N * 2), - DepthConvBlock(N * 2, N * 2), - DepthConvBlock(N * 2, N * 2), - nn.Conv2d(N * 2, N * 2 + 2, 1), + def forward(self, x): + return self.conv(x) + + +class IntraSpatialPrior(nn.Module): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + nn.Conv2d(g_ch_y * 2, g_ch_y * 2, 1), ) - self.y_spatial_prior_reduction = nn.Conv2d(N * 2 + 2, N * 1, 1) - self.y_spatial_prior_adaptor_1 = DepthConvBlock(N * 2, N * 2, force_adaptor=True) - self.y_spatial_prior_adaptor_2 = DepthConvBlock(N * 2, N * 2, force_adaptor=True) - self.y_spatial_prior_adaptor_3 = DepthConvBlock(N * 2, N * 2, force_adaptor=True) - self.y_spatial_prior = nn.Sequential( - DepthConvBlock(N * 2, N * 2), - DepthConvBlock(N * 2, N * 2), - DepthConvBlock(N * 2, N * 2), - nn.Conv2d(N * 2, N * 2, 1), + def forward(self, x): + return self.conv(x) + + +class IntraYPriorFusion(nn.Module): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y, g_ch_y * 2), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + nn.Conv2d(g_ch_y * 2, g_ch_y * 2, 1), ) - self.dec = IntraDecoder(N) + def forward(self, x): + return self.conv(x) + + +class DMCI(CompressionModel): + def __init__(self): + super().__init__(z_channel=g_ch_z) - self.q_scale_enc = nn.Parameter(torch.ones((self.get_qp_num(), g_ch_enc_dec, 1, 1))) - self.q_scale_dec = nn.Parameter(torch.ones((self.get_qp_num(), g_ch_enc_dec, 1, 1))) + self.enc = IntraEncoder() + self.hyper_enc = IntraHyperEncoder() - def compress(self, x, qp): - device = x.device - curr_q_enc = self.q_scale_enc[qp:qp+1, :, :, :] - curr_q_dec = self.q_scale_dec[qp:qp+1, :, :, :] + self.hyper_dec = IntraHyperDecoder() + self.y_prior_fusion = IntraYPriorFusion() + + self.y_spatial_prior_reduction = nn.Conv2d(g_ch_y * 2, g_ch_y, 1) + self.y_spatial_prior_adaptor_1 = DepthConvBlock(g_ch_y * 2, g_ch_y * 2, force_adaptor=True) + self.y_spatial_prior_adaptor_2 = DepthConvBlock(g_ch_y * 2, g_ch_y * 2, force_adaptor=True) + self.y_spatial_prior_adaptor_3 = DepthConvBlock(g_ch_y * 2, g_ch_y * 2, force_adaptor=True) + self.y_spatial_prior = IntraSpatialPrior() + + self.dec = IntraDecoder() + + self.q_scale_enc = nn.Parameter(torch.ones((self.qp_num(), g_ch_enc_dec))) + self.q_scale_dec = nn.Parameter(torch.ones((self.qp_num(), g_ch_enc_dec))) + self.q_scale_y_enc = nn.Parameter(torch.ones((self.qp_num(), g_ch_y))) + self.q_scale_y_dec = nn.Parameter(torch.ones((self.qp_num(), g_ch_y))) + self._initialize_weights() + + def forward_one_frame(self, x, qp, recon_only=False): + curr_q_enc = self.index_select_dim0(self.q_scale_enc, qp) + curr_q_dec = self.index_select_dim0(self.q_scale_dec, qp) + curr_y_q_enc = self.index_select_dim0(self.q_scale_y_enc, qp) + curr_y_q_dec = self.index_select_dim0(self.q_scale_y_dec, qp) y = self.enc(x, curr_q_enc) - y_pad = self.pad_for_y(y) - z = self.hyper_enc(y_pad) - z_hat, z_hat_write = round_and_to_int8(z) + z = self.hyper_enc(y) + z_hat = QuantFunc.apply(z) params = self.hyper_dec(z_hat) params = self.y_prior_fusion(params) _, _, yH, yW = y.shape - params = params[:, :, :yH, :yW].contiguous() - y_q_w_0, y_q_w_1, y_q_w_2, y_q_w_3, s_w_0, s_w_1, s_w_2, s_w_3, y_hat = \ - self.compress_prior_4x( - y, params, self.y_spatial_prior_reduction, - self.y_spatial_prior_adaptor_1, self.y_spatial_prior_adaptor_2, - self.y_spatial_prior_adaptor_3, self.y_spatial_prior) - - cuda_event = torch.cuda.Event() - cuda_event.record() - x_hat = self.dec(y_hat, curr_q_dec).clamp_(0, 1) - - cuda_stream = self.get_cuda_stream(device=device, priority=-1) - with torch.cuda.stream(cuda_stream): - cuda_event.wait() - self.entropy_coder.reset() - self.bit_estimator_z.encode_z(z_hat_write, qp) - self.gaussian_encoder.encode_y(y_q_w_0, s_w_0) - self.gaussian_encoder.encode_y(y_q_w_1, s_w_1) - self.gaussian_encoder.encode_y(y_q_w_2, s_w_2) - self.gaussian_encoder.encode_y(y_q_w_3, s_w_3) - self.entropy_coder.flush() - - bit_stream = self.entropy_coder.get_encoded_stream() - - torch.cuda.synchronize(device=device) - result = { - "bit_stream": bit_stream, - "x_hat": x_hat, + params = params[:, :, :yH, :yW] + y_res, y_q, y_hat, scales_hat = self.forward_prior_4x( + y, curr_y_q_enc, curr_y_q_dec, + params, self.y_spatial_prior_reduction, + self.y_spatial_prior_adaptor_1, self.y_spatial_prior_adaptor_2, + self.y_spatial_prior_adaptor_3, self.y_spatial_prior) + + x_hat = self.dec(y_hat, curr_q_dec) + if recon_only: + return x_hat + + y_for_bit = self.add_noise(y_res) + z_for_bit = self.add_noise(z) + bits_y = self.get_y_bits(y_for_bit, scales_hat) + bits_z = self.get_z_bits(z_for_bit, qp) + + mse = self.get_mse(x, x_hat) + bits_y = torch.sum(bits_y, dim=(1, 2, 3)) + bits_z = torch.sum(bits_z, dim=(1, 2, 3)) + _, _, H, W = x.size() + pixel_num = H * W + bpp = (bits_y + bits_z) / pixel_num + + return { + 'x_hat': x_hat, + 'mse': mse, + 'bpp': bpp, + 'bits_y': bits_y, + 'bits_z': bits_z, } - return result - def decompress(self, bit_stream, sps, qp): - dtype = next(self.parameters()).dtype - device = next(self.parameters()).device - curr_q_dec = self.q_scale_dec[qp:qp+1, :, :, :] - - self.entropy_coder.set_use_two_entropy_coders(sps['ec_part'] == 1) - self.entropy_coder.set_stream(bit_stream) - z_size = self.get_downsampled_shape(sps['height'], sps['width'], 64) - y_height, y_width = self.get_downsampled_shape(sps['height'], sps['width'], 16) - self.bit_estimator_z.decode_z(z_size, qp) - z_q = self.bit_estimator_z.get_z(z_size, device, dtype) - z_hat = z_q + def compress(self, x, qp, padding_b, padding_r): + if self.proxy is None: + try: + from inference_extensions_cuda import DMCIProxy + except Exception: + raise NotImplementedError( + 'cannot import cuda implementation for inference. ' + 'Please build the inference extensions first.' + ) + state_dict = self.state_dict() + state_dict = self.add_cdf_to_state_dict(state_dict) + self.proxy = DMCIProxy() + self.proxy.set_param(state_dict, self.gaussian_encoder.skip_thres) + bit_stream, x_hat, ec_parallel = self.proxy.compress(x, qp, padding_b, padding_r) + return { + 'bit_stream': bit_stream.tobytes(), + 'x_hat': x_hat, + 'ec_parallel': ec_parallel, + } - params = self.hyper_dec(z_hat) - params = self.y_prior_fusion(params) - params = params[:, :, :y_height, :y_width].contiguous() - y_hat = self.decompress_prior_4x(params, self.y_spatial_prior_reduction, - self.y_spatial_prior_adaptor_1, - self.y_spatial_prior_adaptor_2, - self.y_spatial_prior_adaptor_3, self.y_spatial_prior) - - x_hat = self.dec(y_hat, curr_q_dec).clamp_(0, 1) - return {"x_hat": x_hat} + def decompress(self, bit_stream, sps, qp, ec_part): + x_hat = self.proxy.decompress( + np.frombuffer(bit_stream, dtype=np.uint8), qp, sps['height'], sps['width'], ec_part) + return {'x_hat': x_hat} + + def forward(self, x, qp, lambdas=None, get_loss_info=False, recon_only=False): + result = self.forward_one_frame(x, qp, recon_only) + loss = loss_func(result, lambdas) + info = None + if get_loss_info: + _, _, H, W = x.size() + pixel_num = H * W + info = self.get_loss_info(result, loss, pixel_num) + return loss['loss'], info diff --git a/src/models/video_model_ht.py b/src/models/video_model_ht.py new file mode 100644 index 0000000..f4dbaf2 --- /dev/null +++ b/src/models/video_model_ht.py @@ -0,0 +1,526 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import numpy as np +import torch +import torch.nn.functional as F + +from torch import nn + +from .common_model import CkptModule, CompressionModel +from ..layers.layers import SubpelConv2x, DepthConvBlock, QuantFunc, ResidualBlockUpsample, \ + ResidualBlockWithStride2, mse_8frames_sum +from ..utils.common import ModelStructure, loss_func + + +g_frame_delay = 8 +g_ch_src_d_intra = 3 * 8 * 8 +g_ch_src_d = g_ch_src_d_intra * g_frame_delay +g_ch_y = 256 +g_ch_z = 128 +g_ch_d = 512 +g_ch_m = 512 +g_ch_recon = 256 + + +class Decoder(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + self.up = SubpelConv2x(g_ch_y, g_ch_d, 1) + self.conv1 = nn.Sequential( + DepthConvBlock(g_ch_d * 2, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + ) + else: + self.up = SubpelConv2x(g_ch_y, g_ch_d, 3, padding=1, force_bias=True) + self.conv1 = nn.Sequential( + DepthConvBlock(g_ch_d * 2, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + ) + + def internal_forward(self, x, ctx, quant_step): + feature = self.up(x) + feature = self.conv1(torch.cat((feature, ctx), dim=1)) + feature = feature * quant_step + return feature + + +class Encoder(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + self.conv1 = nn.Sequential( + DepthConvBlock(g_ch_src_d + g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + ) + else: + self.conv1 = nn.Sequential( + DepthConvBlock(g_ch_src_d + g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + ) + self.down = nn.Conv2d(g_ch_d, g_ch_y, 3, stride=2, padding=1) + + def internal_forward(self, x, ctx, quant_step): + feature = F.pixel_unshuffle(x, 8) + feature = self.conv1(torch.cat((feature, ctx), dim=1)) + feature = feature * quant_step + feature = self.down(feature) + return feature + + +class FeatureAdaptorI(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + self.conv = nn.Sequential( + DepthConvBlock(g_ch_src_d_intra, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + ) + else: + self.conv = nn.Sequential( + DepthConvBlock(g_ch_src_d_intra, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + ) + + def internal_forward(self, x): + return self.conv(x) + + +class FeatureAdaptorM(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + self.conv = nn.Sequential( + DepthConvBlock(g_ch_m + g_ch_d, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + ) + else: + self.conv = nn.Sequential( + DepthConvBlock(g_ch_m + g_ch_d, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + DepthConvBlock(g_ch_m, g_ch_m), + ) + + def internal_forward(self, memory, feature): + return self.conv(torch.cat((memory, feature), dim=1)) + + +class FeatureExtractor(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + self.conv = nn.Sequential( + DepthConvBlock(g_ch_m, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + ) + else: + self.conv = nn.Sequential( + DepthConvBlock(g_ch_m, g_ch_d), + DepthConvBlock(g_ch_d, g_ch_d), + ) + + def internal_forward(self, x): + return self.conv(x) + + +class HyperDecoder(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + kwargs = {"shortcut": False} + else: + kwargs = {"force_bias": True} + self.conv = nn.Sequential( + ResidualBlockUpsample(g_ch_z, g_ch_y, **kwargs), + ResidualBlockUpsample(g_ch_y, g_ch_y, **kwargs), + DepthConvBlock(g_ch_y, g_ch_y), + ) + + def internal_forward(self, x): + return self.conv(x) + + +class HyperEncoder(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + kwargs = {"shortcut": False} + else: + kwargs = {} + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y, g_ch_y), + ResidualBlockWithStride2(g_ch_y, g_ch_y, **kwargs), + ResidualBlockWithStride2(g_ch_y, g_ch_z, **kwargs), + ) + + def internal_forward(self, x): + return self.conv(x) + + +class PriorFusion(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y * 3, g_ch_y * 3), + DepthConvBlock(g_ch_y * 3, g_ch_y * 3), + DepthConvBlock(g_ch_y * 3, g_ch_y * 3), + nn.Conv2d(g_ch_y * 3, g_ch_y * 3, 1), + ) + + def internal_forward(self, x1, x2): + return self.conv(torch.cat((x1, x2), dim=1)) + + +class ReconHead(CkptModule): + def __init__(self, is_hts): + super().__init__() + self.is_hts = is_hts + if is_hts: + self.conv1 = nn.ModuleList() + for _ in range(g_frame_delay // 2): + self.conv1.append( + nn.Sequential( + DepthConvBlock(g_ch_d, g_ch_d), + ) + ) + + self.conv2 = nn.ModuleList() + for _ in range(g_frame_delay): + self.conv2.append( + nn.Sequential( + DepthConvBlock(g_ch_d, g_ch_recon), + DepthConvBlock(g_ch_recon, g_ch_recon), + DepthConvBlock(g_ch_recon, g_ch_recon), + nn.Conv2d(g_ch_recon, g_ch_src_d_intra, 1), + ) + ) + else: + self.conv = nn.ModuleList() + for _ in range(g_frame_delay): + self.conv.append( + nn.Sequential( + DepthConvBlock(g_ch_d, g_ch_recon), + DepthConvBlock(g_ch_recon, g_ch_recon), + DepthConvBlock(g_ch_recon, g_ch_recon), + DepthConvBlock(g_ch_recon, g_ch_recon), + DepthConvBlock(g_ch_recon, g_ch_recon), + nn.Conv2d(g_ch_recon, g_ch_src_d_intra, 1), + ) + ) + + def internal_forward(self, x, for_reset=False): + if self.is_hts: + if for_reset: + out = self.conv1[-1](x) + return self.conv2[-1](out) + + all_out = [] + for i in range(g_frame_delay): + if i % 2 == 0: + common = self.conv1[i // 2](x) + out = self.conv2[i](common) + out = F.pixel_shuffle(out, 8) + all_out.append(out) + return all_out + else: + if for_reset: + return self.conv[-1](x) + + all_out = [] + for i in range(g_frame_delay): + out = self.conv[i](x) + out = F.pixel_shuffle(out, 8) + all_out.append(out) + return all_out + + +class SpatialPrior(CkptModule): + def __init__(self, is_hts): + super().__init__() + out_ch = g_ch_y * 1 if is_hts else g_ch_y * 2 + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2), + nn.Conv2d(g_ch_y * 2, out_ch, 1), + ) + + def internal_forward(self, x): + return self.conv(x) + + +class SpatialPriorAdaptor(DepthConvBlock): + def __init__(self, in_ch, out_ch, *, dcb2=False, shortcut=False, force_adaptor=True, + is_hts=True): + assert force_adaptor + super().__init__(in_ch, out_ch, dcb2=dcb2, shortcut=shortcut, force_adaptor=force_adaptor) + self.is_hts = is_hts + + def forward(self, x1, x2=None): + if self.is_hts: + return super().forward(torch.cat((x1, x2), dim=1)) + else: + return super().forward(x1) + + +class TemporalPriorEncoder(CkptModule): + def __init__(self, is_hts): + super().__init__() + if is_hts: + kwargs = {"shortcut": False} + else: + kwargs = {} + self.conv = ResidualBlockWithStride2(g_ch_d, g_ch_y * 2, **kwargs) + + def internal_forward(self, x, quant): + return self.conv(x * quant) + + +class DMC(CompressionModel): + def __init__(self, model_structure=ModelStructure.HTS): + super().__init__(z_channel=g_ch_z) + + self.is_hts = model_structure == ModelStructure.HTS + + self.feature_adaptor_i = FeatureAdaptorI(self.is_hts) + self.feature_adaptor_m = FeatureAdaptorM(self.is_hts) + self.feature_extractor = FeatureExtractor(self.is_hts) + + self.encoder = Encoder(self.is_hts) + self.hyper_encoder = HyperEncoder(self.is_hts) + + self.hyper_decoder = HyperDecoder(self.is_hts) + self.temporal_prior_encoder = TemporalPriorEncoder(self.is_hts) + self.y_prior_fusion = PriorFusion() + self.y_spatial_prior_reduction = nn.Conv2d(g_ch_y * 3, g_ch_y, 1) + self.y_spatial_prior_adaptor_1 = SpatialPriorAdaptor( + g_ch_y * 2, g_ch_y * 2, is_hts=self.is_hts) + self.y_spatial_prior_adaptor_2 = SpatialPriorAdaptor( + g_ch_y * 2, g_ch_y * 2, is_hts=self.is_hts) + self.y_spatial_prior_adaptor_3 = SpatialPriorAdaptor( + g_ch_y * 2, g_ch_y * 2, is_hts=self.is_hts) + self.y_spatial_prior = SpatialPrior(self.is_hts) + self.decoder = Decoder(self.is_hts) + + self.recon_head = ReconHead(self.is_hts) + + self.q_encoder = nn.Parameter(torch.ones((self.qp_num(), g_ch_d))) + self.q_decoder = nn.Parameter(torch.ones((self.qp_num(), g_ch_d))) + self.q_feature = nn.Parameter(torch.ones((self.qp_num(), g_ch_d))) + self._initialize_weights() + + self.ref_feature = None + self.memory = None + self.ctx = None + + def apply_feature_adaptor(self): + if self.memory is None: + self.memory = self.feature_adaptor_i(self.ref_feature) + else: + self.memory = self.feature_adaptor_m(self.memory, self.ref_feature) + self.ctx = self.feature_extractor(self.memory) + + def clear_dpb(self): + self.ref_feature = None + self.memory = None + self.ctx = None + + def get_rd_info(self, res): + dist_weights = [1.5, 0.16, 0.4] + assert g_frame_delay == 8 + mse = mse_8frames_sum(res['mse'], dist_weights) + + rd = { + 'bits_y': res['bits_y'], + 'bits_z': res['bits_z'], + 'bpp': res['bpp'], + 'mse': mse, + } + return rd + + def get_recon_and_feature(self, y_hat, ctx, q_decoder): + feature = self.decoder(y_hat, ctx, q_decoder) + x_hat = self.recon_head(feature) + return x_hat, feature + + def res_prior_param_decoder(self, z_hat, memory, q_feature): + temporal_params = self.temporal_prior_encoder(memory, q_feature) + hyper_params = self.hyper_decoder(z_hat) + params = self.y_prior_fusion(hyper_params, temporal_params) + return params + + def set_use_ckpt(self, use_ckpt=True): + self.feature_adaptor_i.set_use_ckpt(use_ckpt) + self.feature_adaptor_m.set_use_ckpt(use_ckpt) + self.feature_extractor.set_use_ckpt(use_ckpt) + self.temporal_prior_encoder.set_use_ckpt(use_ckpt) + self.encoder.set_use_ckpt(use_ckpt) + self.decoder.set_use_ckpt(use_ckpt) + self.recon_head.set_use_ckpt(use_ckpt) + self.hyper_encoder.set_use_ckpt(use_ckpt) + self.hyper_decoder.set_use_ckpt(use_ckpt) + self.y_prior_fusion.set_use_ckpt(use_ckpt) + self.y_spatial_prior.set_use_ckpt(use_ckpt) + + def set_ref_feature(self, feature, reset_feature_memory): + self.ref_feature = feature + if reset_feature_memory: + feature = self.recon_head(feature, for_reset=True) + self.clear_dpb() + self.ref_feature = feature + + def add_ref_feature_from_frame(self, frame, apply_feature_adaptor=True): + if self.training: + self.ref_feature = F.pixel_unshuffle(frame, 8) + return + if self.proxy is None: + try: + if self.is_hts: + from inference_extensions_cuda import DMCHTSProxy + proxy_cls = DMCHTSProxy + else: + from inference_extensions_cuda import DMCHTLProxy + proxy_cls = DMCHTLProxy + except Exception: + raise NotImplementedError( + 'cannot import cuda implementation for inference. ' + 'Please build the inference extensions first.' + ) + state_dict = self.state_dict() + state_dict = self.add_cdf_to_state_dict(state_dict) + self.proxy = proxy_cls() + self.proxy.set_param(state_dict, self.gaussian_encoder.skip_thres) + return self.proxy.add_ref_feature_from_frame(frame, apply_feature_adaptor) + + def compress(self, x, qp, reset_feature_memory, padding_b, padding_r): + bit_stream, ec_parallel = self.proxy.compress( + x, qp, reset_feature_memory, padding_b, padding_r) + return { + 'bit_stream': bit_stream.tobytes(), + 'ec_parallel': ec_parallel, + } + + def decompress(self, bit_stream, sps, qp, ec_part, reset_feature_memory): + x_hat = self.proxy.decompress((np.frombuffer(bit_stream, dtype=np.uint8)), + qp, sps['height'], sps['width'], ec_part, + reset_feature_memory) + return { + 'x_hat': x_hat, + } + + def forward_one_frame(self, x, qp, reset_feature_memory=False): + q_encoder = self.index_select_dim0(self.q_encoder, qp) + q_decoder = self.index_select_dim0(self.q_decoder, qp) + q_feature = self.index_select_dim0(self.q_feature, qp) + self.apply_feature_adaptor() + + y = self.encoder(x, self.ctx, q_encoder) + + z = self.hyper_encoder(y) + z_hat = QuantFunc.apply(z) + + params = self.res_prior_param_decoder(z_hat, self.memory, q_feature) + y_res, y_q, y_hat, scales_hat = self.forward_prior_4x( + y, None, None, params, self.y_spatial_prior_reduction, + self.y_spatial_prior_adaptor_1, self.y_spatial_prior_adaptor_2, + self.y_spatial_prior_adaptor_3, self.y_spatial_prior, + spatial_prior_has_scales=not self.is_hts) + + x_hat, feature = self.get_recon_and_feature(y_hat, self.ctx, q_decoder) + + self.set_ref_feature(feature, reset_feature_memory) + + y_for_bit = self.add_noise(y_res) + z_for_bit = self.add_noise(z) + bits_y = self.get_y_bits(y_for_bit, scales_hat) + bits_z = self.get_z_bits(z_for_bit, qp) + + x_split = x.chunk(g_frame_delay, 1) + mse_list = [] + for x_one, x_hat_one in zip(x_split, x_hat): + mse = self.get_mse(x_one, x_hat_one) + mse_list.append(mse) + bits_y = torch.sum(bits_y, dim=(1, 2, 3)) + bits_z = torch.sum(bits_z, dim=(1, 2, 3)) + _, _, H, W = x.size() + pixel_num = H * W + bpp = (bits_y + bits_z) / pixel_num + + return { + 'bits_y': bits_y, + 'bits_z': bits_z, + 'bpp': bpp, + 'mse': mse_list, + 'x_hat': x_hat, + } + + def forward(self, x, qp, lambdas=None, get_loss_info=False, curr_poc=0): + if not isinstance(x, list): + result = self.forward_one_frame(x, qp) + rd = self.get_rd_info(result) + loss = loss_func(rd, lambdas) + self.ref_feature = self.ref_feature.detach() + self.memory = self.memory.detach() + info = None + if get_loss_info: + _, _, H, W = x.size() + pixel_num = H * W + info = self.get_loss_info(rd, loss, pixel_num) + return loss['loss'], info + + frame_nums = len(x) + losses = [] + for frame_index in range(frame_nums): + cur_frame = x[frame_index] + result = self.forward_one_frame(cur_frame, qp) + rd = self.get_rd_info(result) + loss = loss_func(rd, lambdas) + losses.append(loss['loss']) + info = None + if get_loss_info: + _, _, H, W = x[0].size() + pixel_num = H * W + info = self.get_loss_info(rd, loss, pixel_num) + loss = torch.mean(torch.stack(losses)) + return loss, info diff --git a/src/models/video_model_ld.py b/src/models/video_model_ld.py new file mode 100644 index 0000000..24091b3 --- /dev/null +++ b/src/models/video_model_ld.py @@ -0,0 +1,376 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import numpy as np +import torch +import torch.nn.functional as F + +from torch import nn + +from .common_model import CkptModule, CompressionModel +from ..layers.layers import SubpelConv2x, DepthConvBlock, QuantFunc, ResidualBlockUpsample, \ + ResidualBlockWithStride2 +from ..utils.common import loss_func + + +g_frame_delay = 1 +g_ch_src_d = 3 * 8 * 8 +g_ch_y = 128 +g_ch_z = 128 +g_ch_d = 256 +g_ch_m = 256 + + +class Decoder(CkptModule): + def __init__(self): + super().__init__() + self.up = SubpelConv2x(g_ch_y, g_ch_d, 1) + self.conv1 = nn.Sequential( + DepthConvBlock(g_ch_d + g_ch_m, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + ) + self.conv2 = nn.Conv2d(g_ch_d, g_ch_d, 1) + + def internal_forward(self, x, ctx, quant_step): + feature = self.up(x) + feature = self.conv1(torch.cat((feature, ctx), dim=1)) + feature = self.conv2(feature) + feature = feature * quant_step + return feature + + +class Encoder(CkptModule): + def __init__(self): + super().__init__() + self.conv1 = nn.Sequential( + DepthConvBlock(g_ch_src_d + g_ch_m, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + ) + self.conv2 = DepthConvBlock(g_ch_d, g_ch_d, dcb2=True) + self.down = nn.Conv2d(g_ch_d, g_ch_y, 3, stride=2, padding=1) + + def internal_forward(self, x, ctx, quant_step): + feature = F.pixel_unshuffle(x, 8) + feature = self.conv1(torch.cat((feature, ctx), dim=1)) + feature = self.conv2(feature) + feature = feature * quant_step + feature = self.down(feature) + return feature + + +class FeatureAdaptorI(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_src_d, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + ) + + self.proxy = None + + def internal_forward(self, x): + return self.conv(x) + + +class FeatureAdaptorM(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_m + g_ch_d, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + ) + + def internal_forward(self, memory, feature): + return self.conv(torch.cat((memory, feature), dim=1)) + + +class FeatureExtractor(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + DepthConvBlock(g_ch_m, g_ch_m, dcb2=True), + ) + + self.proxy = None + + def internal_forward(self, x): + return self.conv(x) + + +class HyperDecoder(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + ResidualBlockUpsample(g_ch_z, g_ch_z, dcb2=True, shortcut=False), + ResidualBlockUpsample(g_ch_z, g_ch_z, dcb2=True, shortcut=False), + DepthConvBlock(g_ch_z, g_ch_y, dcb2=True), + ) + + self.proxy = None + + def internal_forward(self, x): + return self.conv(x) + + +class HyperEncoder(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y, g_ch_z, dcb2=True), + ResidualBlockWithStride2(g_ch_z, g_ch_z, dcb2=True, shortcut=False), + ResidualBlockWithStride2(g_ch_z, g_ch_z, dcb2=True, shortcut=False), + ) + + def internal_forward(self, x): + return self.conv(x) + + +class PriorFusion(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y * 3, g_ch_y * 3, dcb2=True), + DepthConvBlock(g_ch_y * 3, g_ch_y * 3, dcb2=True), + DepthConvBlock(g_ch_y * 3, g_ch_y * 3, dcb2=True), + nn.Conv2d(g_ch_y * 3, g_ch_y * 3, 1), + ) + + def internal_forward(self, x1, x2, quant): + return self.conv(torch.cat((x1, x2 * quant), dim=1)) + + +class ReconHead(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + DepthConvBlock(g_ch_d, g_ch_d, dcb2=True), + ) + self.head = nn.Conv2d(g_ch_d, g_ch_src_d, 1) + + def internal_forward(self, x, for_reset=False): + out = self.conv(x) + out = self.head(out) + if for_reset: + return out + return F.pixel_shuffle(out, 8) + + +class SpatialPrior(CkptModule): + def __init__(self): + super().__init__() + self.conv = nn.Sequential( + DepthConvBlock(g_ch_y * 4, g_ch_y * 2, dcb2=True), + DepthConvBlock(g_ch_y * 2, g_ch_y * 2, dcb2=True), + nn.Conv2d(g_ch_y * 2, g_ch_y * 1, 1), + ) + + def internal_forward(self, x1, x2): + return self.conv(torch.cat((x1, x2), dim=1)) + + +class TemporalPriorEncoder(CkptModule): + def __init__(self): + super().__init__() + self.conv = ResidualBlockWithStride2(g_ch_m, g_ch_y * 2, dcb2=True, shortcut=False) + + def internal_forward(self, x): + return self.conv(x) + + +class DMC(CompressionModel): + def __init__(self): + super().__init__(z_channel=g_ch_z) + + self.feature_adaptor_i = FeatureAdaptorI() + self.feature_adaptor_m = FeatureAdaptorM() + self.feature_extractor = FeatureExtractor() + + self.encoder = Encoder() + self.hyper_encoder = HyperEncoder() + + self.hyper_decoder = HyperDecoder() + self.temporal_prior_encoder = TemporalPriorEncoder() + self.y_prior_fusion = PriorFusion() + self.y_spatial_prior = SpatialPrior() + self.decoder = Decoder() + + self.recon_head = ReconHead() + + self.q_encoder = nn.Parameter(torch.ones((self.qp_num(), g_ch_d))) + self.q_decoder = nn.Parameter(torch.ones((self.qp_num(), g_ch_d))) + self.q_feature = nn.Parameter(torch.ones((self.qp_num(), g_ch_y * 2))) + self._initialize_weights() + + self.ref_feature = None + self.memory = None + self.ctx = None + + def apply_feature_adaptor(self): + if self.memory is None: + self.memory = self.feature_adaptor_i(self.ref_feature) + else: + self.memory = self.feature_adaptor_m(self.memory, self.ref_feature) + self.ctx = self.feature_extractor(self.memory) + + def clear_dpb(self): + self.ref_feature = None + self.memory = None + self.ctx = None + + def get_rd_info(self, result, fa_idx): + dist_weights = [0.52, 1.33, 0.83] + dist_weight = dist_weights[fa_idx] + rd = { + 'bits_y': result['bits_y'], + 'bits_z': result['bits_z'], + 'bpp': result['bpp'], + 'mse': result['mse'] * dist_weight, + } + return rd + + def get_recon_and_feature(self, y_hat, ctx, q_decoder): + feature = self.decoder(y_hat, ctx, q_decoder) + x_hat = self.recon_head(feature) + return x_hat, feature + + def res_prior_param_decoder(self, z_hat, memory, q_feature): + temporal_params = self.temporal_prior_encoder(memory) + hyper_params = self.hyper_decoder(z_hat) + params = self.y_prior_fusion(hyper_params, temporal_params, q_feature) + return params + + def set_use_ckpt(self, use_ckpt=True): + self.feature_adaptor_i.set_use_ckpt(use_ckpt) + self.feature_adaptor_m.set_use_ckpt(use_ckpt) + self.feature_extractor.set_use_ckpt(use_ckpt) + self.temporal_prior_encoder.set_use_ckpt(use_ckpt) + self.encoder.set_use_ckpt(use_ckpt) + self.decoder.set_use_ckpt(use_ckpt) + self.recon_head.set_use_ckpt(use_ckpt) + self.hyper_encoder.set_use_ckpt(use_ckpt) + self.hyper_decoder.set_use_ckpt(use_ckpt) + self.y_prior_fusion.set_use_ckpt(use_ckpt) + self.y_spatial_prior.set_use_ckpt(use_ckpt) + + def set_ref_feature(self, feature, reset_feature_memory): + self.ref_feature = feature + if reset_feature_memory: + feature = self.recon_head(feature, for_reset=True) + self.clear_dpb() + self.ref_feature = feature + + def add_ref_feature_from_frame(self, frame, apply_feature_adaptor=True): + if self.training: + self.ref_feature = F.pixel_unshuffle(frame, 8) + return + if self.proxy is None: + try: + from inference_extensions_cuda import DMCLDProxy + except Exception: + raise NotImplementedError( + 'cannot import cuda implementation for inference. ' + 'Please build the inference extensions first.' + ) + state_dict = self.state_dict() + state_dict = self.add_cdf_to_state_dict(state_dict) + self.proxy = DMCLDProxy() + self.proxy.set_param(state_dict, self.gaussian_encoder.skip_thres) + return self.proxy.add_ref_feature_from_frame(frame, apply_feature_adaptor) + + def compress(self, x, qp, reset_feature_memory, padding_b, padding_r): + bit_stream, ec_parallel = self.proxy.compress( + x, qp, reset_feature_memory, padding_b, padding_r) + return { + 'bit_stream': bit_stream.tobytes(), + 'ec_parallel': ec_parallel, + } + + def decompress(self, bit_stream, sps, qp, ec_part, reset_feature_memory): + x_hat = self.proxy.decompress((np.frombuffer(bit_stream, dtype=np.uint8)), + qp, sps['height'], sps['width'], ec_part, + reset_feature_memory) + + return { + 'x_hat': x_hat, + } + + def forward_one_frame(self, x, qp, reset_feature_memory=False): + q_encoder = self.index_select_dim0(self.q_encoder, qp) + q_decoder = self.index_select_dim0(self.q_decoder, qp) + q_feature = self.index_select_dim0(self.q_feature, qp) + self.apply_feature_adaptor() + + y = self.encoder(x, self.ctx, q_encoder) + + z = self.hyper_encoder(y) + z_hat = QuantFunc.apply(z) + + params = self.res_prior_param_decoder(z_hat, self.memory, q_feature) + y_res, y_q, y_hat, scales_hat = self.forward_prior_2x(y, params, self.y_spatial_prior) + + x_hat, feature = self.get_recon_and_feature(y_hat, self.ctx, q_decoder) + + self.set_ref_feature(feature, reset_feature_memory) + + y_for_bit = self.add_noise(y_res) + z_for_bit = self.add_noise(z) + bits_y = self.get_y_bits(y_for_bit, scales_hat) + bits_z = self.get_z_bits(z_for_bit, qp) + + mse = self.get_mse(x, x_hat) + bits_y = torch.sum(bits_y, dim=(1, 2, 3)) + bits_z = torch.sum(bits_z, dim=(1, 2, 3)) + _, _, H, W = x.size() + pixel_num = H * W + bpp = (bits_y + bits_z) / pixel_num + + return {'bits_y': bits_y, + 'bits_z': bits_z, + 'bpp': bpp, + 'mse': mse, + 'x_hat': x_hat, + } + + def forward(self, x, qp, lambdas=None, get_loss_info=False, curr_poc=0): + index_map = [0, 1, 0, 2, 0, 2, 0, 2] + if not isinstance(x, list): + fa_idx = index_map[curr_poc % 8] + result = self.forward_one_frame(x, qp) + rd = self.get_rd_info(result, fa_idx) + loss = loss_func(rd, lambdas) + self.ref_feature = self.ref_feature.detach() + self.memory = self.memory.detach() + info = None + if get_loss_info: + _, _, H, W = x.size() + pixel_num = H * W + info = self.get_loss_info(rd, loss, pixel_num) + return loss['loss'], info + + frame_nums = len(x) + losses = [] + for frame_index in range(frame_nums): + cur_frame = x[frame_index] + fa_idx = index_map[(frame_index + 1) % 8] + result = self.forward_one_frame(cur_frame, qp) + rd = self.get_rd_info(result, fa_idx) + loss = loss_func(rd, lambdas) + losses.append(loss['loss']) + info = None + if get_loss_info: + _, _, H, W = x[0].size() + pixel_num = H * W + info = self.get_loss_info(rd, loss, pixel_num) + loss = torch.mean(torch.stack(losses)) + return loss, info diff --git a/src/utils/common.py b/src/utils/common.py index a7599c0..a370b9e 100644 --- a/src/utils/common.py +++ b/src/utils/common.py @@ -2,58 +2,41 @@ # Licensed under the MIT License. import json +import numpy as np import os -from unittest.mock import patch - import torch -from torch.nn.modules.utils import consume_prefix_in_state_dict_if_present -import numpy as np - +import torch.distributed as dist +import torch.multiprocessing as mp -def str2bool(v): - return str(v).lower() in ("yes", "y", "true", "t", "1") +from enum import Enum +from torch.nn.modules.utils import consume_prefix_in_state_dict_if_present +from torch.nn.parallel import DistributedDataParallel as DDP +from torch.utils.data import DataLoader, RandomSampler +from torch.utils.data.distributed import DistributedSampler +from unittest.mock import patch -def set_torch_env(): - os.environ['CUBLAS_WORKSPACE_CONFIG'] = ":4096:8" - torch.backends.cudnn.enabled = True - torch.backends.cudnn.benchmark = False - torch.use_deterministic_algorithms(True) - torch.manual_seed(0) - torch.set_num_threads(1) - np.random.seed(seed=0) - try: - # require pytorch >= 2.2.0 - torch.utils.deterministic.fill_uninitialized_memory = False - except Exception: # pylint: disable=W0718 - pass +def cleanup_train(rank): + if rank >= 0: + dist.destroy_process_group() def create_folder(path, print_if_create=False): if not os.path.exists(path): os.makedirs(path) if print_if_create: - print(f"created folder: {path}") - - -def get_state_dict(ckpt_path): - ckpt = torch.load(ckpt_path, map_location=torch.device('cpu'), weights_only=True) - if "state_dict" in ckpt: - ckpt = ckpt['state_dict'] - if "net" in ckpt: - ckpt = ckpt["net"] - consume_prefix_in_state_dict_if_present(ckpt, prefix="module.") - return ckpt + print(f'created folder: {path}') @patch('json.encoder.c_make_encoder', None) def dump_json(obj, fid, float_digits=-1, **kwargs): - of = json.encoder._make_iterencode # pylint: disable=W0212 + of = json.encoder._make_iterencode def inner(*args, **kwargs): args = list(args) - # fifth argument is float formater which we will replace - args[4] = lambda o: format(o, '.%df' % float_digits) + # fifth argument is float formatter which we may replace + if float_digits is not None and float_digits >= 0: + args[4] = lambda o: format(o, f'.{int(float_digits)}f') return of(*args, **kwargs) with patch('json.encoder._make_iterencode', wraps=inner): @@ -64,114 +47,252 @@ def generate_log_json(frame_num, frame_pixel_num, test_time, frame_types, bits, verbose=False, avg_encoding_time=None, avg_decoding_time=None): include_yuv = len(psnrs[0]) > 1 assert not include_yuv or (len(psnrs[0]) == 4 and len(ssims[0]) == 4) - i_bits = 0 - i_psnr = 0 - i_psnr_y = 0 - i_psnr_u = 0 - i_psnr_v = 0 - i_ssim = 0 - i_ssim_y = 0 - i_ssim_u = 0 - i_ssim_v = 0 - p_bits = 0 - p_psnr = 0 - p_psnr_y = 0 - p_psnr_u = 0 - p_psnr_v = 0 - p_ssim = 0 - p_ssim_y = 0 - p_ssim_u = 0 - p_ssim_v = 0 - i_num = 0 - p_num = 0 + + # Accumulate stats for i-frames (frame_type==0) and p-frames (frame_type!=0) + metrics = ['psnr', 'ssim'] + (['psnr_y', 'psnr_u', 'psnr_v', 'ssim_y', 'ssim_u', 'ssim_v'] + if include_yuv else []) + metric_idx = {'psnr': 0, 'ssim': 0, 'psnr_y': 1, 'psnr_u': 2, 'psnr_v': 3, + 'ssim_y': 1, 'ssim_u': 2, 'ssim_v': 3} + i_sum = {m: 0 for m in metrics} + p_sum = {m: 0 for m in metrics} + i_sum['bits'], p_sum['bits'] = 0, 0 + i_num, p_num = 0, 0 + for idx in range(frame_num): - if frame_types[idx] == 0: - i_bits += bits[idx] - i_psnr += psnrs[idx][0] - i_ssim += ssims[idx][0] + is_i_frame = frame_types[idx] == 0 + target = i_sum if is_i_frame else p_sum + target['bits'] += bits[idx] + for m in metrics: + src = psnrs if 'psnr' in m else ssims + target[m] += src[idx][metric_idx[m]] + if is_i_frame: i_num += 1 - if include_yuv: - i_psnr_y += psnrs[idx][1] - i_psnr_u += psnrs[idx][2] - i_psnr_v += psnrs[idx][3] - i_ssim_y += ssims[idx][1] - i_ssim_u += ssims[idx][2] - i_ssim_v += ssims[idx][3] else: - p_bits += bits[idx] - p_psnr += psnrs[idx][0] - p_ssim += ssims[idx][0] p_num += 1 - if include_yuv: - p_psnr_y += psnrs[idx][1] - p_psnr_u += psnrs[idx][2] - p_psnr_v += psnrs[idx][3] - p_ssim_y += ssims[idx][1] - p_ssim_u += ssims[idx][2] - p_ssim_v += ssims[idx][3] - - log_result = {} - log_result['frame_pixel_num'] = frame_pixel_num - log_result['i_frame_num'] = i_num - log_result['p_frame_num'] = p_num - log_result['ave_i_frame_bpp'] = i_bits / i_num / frame_pixel_num - log_result['ave_i_frame_psnr'] = i_psnr / i_num - log_result['ave_i_frame_msssim'] = i_ssim / i_num - if include_yuv: - log_result['ave_i_frame_psnr_y'] = i_psnr_y / i_num - log_result['ave_i_frame_psnr_u'] = i_psnr_u / i_num - log_result['ave_i_frame_psnr_v'] = i_psnr_v / i_num - log_result['ave_i_frame_msssim_y'] = i_ssim_y / i_num - log_result['ave_i_frame_msssim_u'] = i_ssim_u / i_num - log_result['ave_i_frame_msssim_v'] = i_ssim_v / i_num + + log_result = { + 'frame_pixel_num': frame_pixel_num, + 'i_frame_num': i_num, + 'p_frame_num': p_num, + } + for prefix, num, sums in [('i', i_num, i_sum), ('p', p_num, p_sum)]: + log_result[f'ave_{prefix}_frame_bpp'] = ( + sums['bits'] / num / frame_pixel_num if num > 0 else 0) + log_result[f'ave_{prefix}_frame_psnr'] = sums['psnr'] / num if num > 0 else 0 + log_result[f'ave_{prefix}_frame_msssim'] = sums['ssim'] / num if num > 0 else 0 + if include_yuv: + for suffix in ['y', 'u', 'v']: + log_result[f'ave_{prefix}_frame_psnr_{suffix}'] = ( + sums[f'psnr_{suffix}'] / num if num > 0 else 0) + log_result[f'ave_{prefix}_frame_msssim_{suffix}'] = ( + sums[f'ssim_{suffix}'] / num if num > 0 else 0) + if verbose: log_result['frame_bpp'] = list(np.array(bits) / frame_pixel_num) log_result['frame_psnr'] = [v[0] for v in psnrs] log_result['frame_msssim'] = [v[0] for v in ssims] log_result['frame_type'] = frame_types if include_yuv: - log_result['frame_psnr_y'] = [v[1] for v in psnrs] - log_result['frame_psnr_u'] = [v[2] for v in psnrs] - log_result['frame_psnr_v'] = [v[3] for v in psnrs] - log_result['frame_msssim_y'] = [v[1] for v in ssims] - log_result['frame_msssim_u'] = [v[2] for v in ssims] - log_result['frame_msssim_v'] = [v[3] for v in ssims] + for suffix, idx in [('y', 1), ('u', 2), ('v', 3)]: + log_result[f'frame_psnr_{suffix}'] = [v[idx] for v in psnrs] + log_result[f'frame_msssim_{suffix}'] = [v[idx] for v in ssims] + log_result['test_time'] = test_time - if p_num > 0: - total_p_pixel_num = p_num * frame_pixel_num - log_result['ave_p_frame_bpp'] = p_bits / total_p_pixel_num - log_result['ave_p_frame_psnr'] = p_psnr / p_num - log_result['ave_p_frame_msssim'] = p_ssim / p_num - if include_yuv: - log_result['ave_p_frame_psnr_y'] = p_psnr_y / p_num - log_result['ave_p_frame_psnr_u'] = p_psnr_u / p_num - log_result['ave_p_frame_psnr_v'] = p_psnr_v / p_num - log_result['ave_p_frame_msssim_y'] = p_ssim_y / p_num - log_result['ave_p_frame_msssim_u'] = p_ssim_u / p_num - log_result['ave_p_frame_msssim_v'] = p_ssim_v / p_num - else: - log_result['ave_p_frame_bpp'] = 0 - log_result['ave_p_frame_psnr'] = 0 - log_result['ave_p_frame_msssim'] = 0 - if include_yuv: - log_result['ave_p_frame_psnr_y'] = 0 - log_result['ave_p_frame_psnr_u'] = 0 - log_result['ave_p_frame_psnr_v'] = 0 - log_result['ave_p_frame_msssim_y'] = 0 - log_result['ave_p_frame_msssim_u'] = 0 - log_result['ave_p_frame_msssim_v'] = 0 - log_result['ave_all_frame_bpp'] = (i_bits + p_bits) / (frame_num * frame_pixel_num) - log_result['ave_all_frame_psnr'] = (i_psnr + p_psnr) / frame_num - log_result['ave_all_frame_msssim'] = (i_ssim + p_ssim) / frame_num + + total_bits = i_sum['bits'] + p_sum['bits'] + log_result['ave_all_frame_bpp'] = total_bits / (frame_num * frame_pixel_num) + log_result['ave_all_frame_psnr'] = (i_sum['psnr'] + p_sum['psnr']) / frame_num + log_result['ave_all_frame_msssim'] = (i_sum['ssim'] + p_sum['ssim']) / frame_num if avg_encoding_time is not None and avg_decoding_time is not None: log_result['avg_frame_encoding_time'] = avg_encoding_time log_result['avg_frame_decoding_time'] = avg_decoding_time if include_yuv: - log_result['ave_all_frame_psnr_y'] = (i_psnr_y + p_psnr_y) / frame_num - log_result['ave_all_frame_psnr_u'] = (i_psnr_u + p_psnr_u) / frame_num - log_result['ave_all_frame_psnr_v'] = (i_psnr_v + p_psnr_v) / frame_num - log_result['ave_all_frame_msssim_y'] = (i_ssim_y + p_ssim_y) / frame_num - log_result['ave_all_frame_msssim_u'] = (i_ssim_u + p_ssim_u) / frame_num - log_result['ave_all_frame_msssim_v'] = (i_ssim_v + p_ssim_v) / frame_num + for suffix in ['y', 'u', 'v']: + log_result[f'ave_all_frame_psnr_{suffix}'] = ( + i_sum[f'psnr_{suffix}'] + p_sum[f'psnr_{suffix}']) / frame_num + log_result[f'ave_all_frame_msssim_{suffix}'] = ( + i_sum[f'ssim_{suffix}'] + p_sum[f'ssim_{suffix}']) / frame_num return log_result + + +def generate_str(x): + return ' '.join(f'{a.item():.5f}' for a in x) + ' ' + + +def get_current_device(rank): + if rank <= 0: + print(f'cuda device count: {torch.cuda.device_count()}') + + if rank >= 0: + device = f'cuda:{rank}' + elif torch.cuda.device_count() > 0: + device = 'cuda:0' + else: + device = 'cpu' + print(f'rank: {rank}, current device: {device}') + return device + + +def get_dataloader(dataset, rank, world_size, batch_size, num_workers): + if rank >= 0: + train_sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank) + assert batch_size % world_size == 0 + arg_batch_size = batch_size // world_size + else: + train_sampler = RandomSampler(dataset) + arg_batch_size = batch_size + return DataLoader( + dataset, + batch_size=arg_batch_size, + num_workers=num_workers, + shuffle=False, + pin_memory=True, + drop_last=True, + sampler=train_sampler, + prefetch_factor=2, + ) + + +def get_latest_status_path(dir_cur): + files = os.listdir(dir_cur) + all_status_files = [os.path.join(dir_cur, f) for f in files if 'status_epo' in f] + all_status_files.sort(key=os.path.getmtime) + if len(all_status_files) > 2: + return all_status_files[-2:] + return all_status_files + + +def loss_func(rd, lambdas): + costs = lambdas * rd['mse'] + rd['bpp'] + return { + 'losses': costs, + 'loss': torch.mean(costs), + } + + +def get_state_dict(ckpt_path): + ckpt = torch.load(ckpt_path, map_location=torch.device('cpu'), weights_only=True) + if 'state_dict' in ckpt: + ckpt = ckpt['state_dict'] + if 'net' in ckpt: + ckpt = ckpt['net'] + consume_prefix_in_state_dict_if_present(ckpt, prefix='module.') + return ckpt + + +def get_training_lambdas(lambdas, qp_num): + all_lambdas = np.linspace(np.log(lambdas[0]), np.log(lambdas[1]), qp_num) + all_lambdas = np.exp(all_lambdas) + return all_lambdas + + +def init_train(rank, save_dir): + torch.backends.cudnn.enabled = True + torch.backends.cudnn.benchmark = True + torch.backends.cuda.matmul.allow_tf32 = True + torch.backends.cudnn.allow_tf32 = True + world_size = 1 + if rank >= 0: + torch.cuda.set_device(rank) + world_size = torch.cuda.device_count() + dist.init_process_group(backend='nccl', init_method='env://', + world_size=world_size, rank=rank) + + if rank <= 0: + create_folder(save_dir) + + return world_size + + +def load_existing_weights(save_dir, net, rank, pretrain_path=None): + begin_epoch = 0 + opt_status = None + ckpt_loaded = False + existing_status_path = get_latest_status_path(save_dir) + for status_path in reversed(existing_status_path): + try: + status = torch.load(status_path, map_location=torch.device('cpu'), + weights_only=True) + opt_status = status['opt'] + begin_epoch = status['epoch'] + 1 + ckpt_loaded = True + if rank <= 0: + net_status = status['net'] + consume_prefix_in_state_dict_if_present(net_status, prefix='module.') + net.load_state_dict(net_status) + print(f'load status from {status_path}') + print(f'begin epoch {begin_epoch}') + break + except Exception: + continue + + if not ckpt_loaded and pretrain_path is not None: + if rank <= 0: + net_state_dict = get_state_dict(pretrain_path) + net.load_state_dict(net_state_dict) + print(f'load pretrained weights from {pretrain_path}') + + return begin_epoch, opt_status + + +def save_ckpt(save_dir, net): + ckpt_path = os.path.join(save_dir, 'ckpt.pth.tar') + net = net.module if isinstance(net, DDP) else net + torch.save({'state_dict': net.state_dict()}, ckpt_path) + print(f'save final checkpoint to {ckpt_path}') + + +def save_status(save_dir, net, opt, epoch): + curr_path = os.path.join(save_dir, f'status_epo{epoch}.pth.tar') + net = net.module if isinstance(net, DDP) else net + save_dict = { + 'epoch': epoch, + 'net': net.state_dict(), + 'opt': opt.state_dict(), + } + torch.save(save_dict, curr_path) + print(f'save model epoch {epoch}') + + for f in os.listdir(save_dir): + full_path = os.path.join(save_dir, f) + if 'status_epo' in f and full_path != curr_path: + if os.path.exists(full_path): + os.remove(full_path) + + +def set_torch_env(): + os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8' + torch.backends.cudnn.enabled = True + torch.backends.cudnn.benchmark = False + torch.use_deterministic_algorithms(True) + torch.manual_seed(0) + torch.set_num_threads(1) + np.random.seed(seed=0) + torch.utils.deterministic.fill_uninitialized_memory = False + + +def start_train(train_fun, args): + if torch.cuda.device_count() > 1: + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = str(12355) + world_size = torch.cuda.device_count() + mp.spawn(train_fun, nprocs=world_size, args=(args,), join=True) + else: + train_fun(-1, args) + + +def str2bool(v): + return str(v).lower() in ['yes', 'y', 'true', 't', '1'] + + +def wrap_ddp(net, rank, find_unused_parameters=False): + if rank >= 0: + net = DDP(net, device_ids=[rank], find_unused_parameters=find_unused_parameters) + return net + + +class ModelStructure(Enum): + HTL = 'htl' + HTS = 'hts' + LD = 'ld' diff --git a/src/utils/metrics.py b/src/utils/metrics.py index 869a9ab..111e3fa 100644 --- a/src/utils/metrics.py +++ b/src/utils/metrics.py @@ -2,8 +2,26 @@ # Licensed under the MIT License. import numpy as np -from scipy import signal + from scipy import ndimage +from scipy import signal + + +def calc_psnr(img1, img2, data_range=255): + ''' + img1 and img2 are arrays with same shape + ''' + img1 = img1.astype(np.float64) + img2 = img2.astype(np.float64) + mse = np.mean(np.square(img1 - img2)) + if np.isnan(mse) or np.isinf(mse): + return -999.9 + if mse > 1e-10: + psnr = 10 * np.log10(data_range * data_range / mse) + else: + psnr = 999.9 + psnr = min(psnr, 99.9) + return psnr def fspecial_gauss(size, sigma): @@ -58,14 +76,11 @@ def calc_msssim(img1, img2, data_range=255): ssim_map, cs_map = calc_ssim(im1, im2, data_range=data_range) mssim = np.append(mssim, ssim_map.mean()) mcs = np.append(mcs, cs_map.mean()) - filtered_im1 = ndimage.filters.convolve(im1, downsample_filter, - mode='reflect') - filtered_im2 = ndimage.filters.convolve(im2, downsample_filter, - mode='reflect') + filtered_im1 = ndimage.convolve(im1, downsample_filter, mode='reflect') + filtered_im2 = ndimage.convolve(im2, downsample_filter, mode='reflect') im1 = filtered_im1[::2, ::2] im2 = filtered_im2[::2, ::2] - return (np.prod(mcs[0:level - 1]**weight[0:level - 1]) * - (mssim[level - 1]**weight[level - 1])) + return (np.prod(mcs[0:level - 1]**weight[0:level - 1]) * (mssim[level - 1]**weight[level - 1])) def calc_msssim_rgb(img1, img2, data_range=255): @@ -76,21 +91,3 @@ def calc_msssim_rgb(img1, img2, data_range=255): for i in range(3): msssim += calc_msssim(img1[i, :, :], img2[i, :, :], data_range) return msssim / 3 - - -def calc_psnr(img1, img2, data_range=255): - ''' - img1 and img2 are arrays with same shape - ''' - img1 = img1.astype(np.float64) - img2 = img2.astype(np.float64) - mse = np.mean(np.square(img1 - img2)) - if np.isnan(mse) or np.isinf(mse): - return -999.9 - if mse > 1e-10: - psnr = 10 * np.log10(data_range * data_range / mse) - else: - psnr = 999.9 - if psnr > 99.9: - psnr = 99.9 - return psnr diff --git a/src/utils/stream_helper.py b/src/utils/stream_helper.py index 1450782..d9e633f 100644 --- a/src/utils/stream_helper.py +++ b/src/utils/stream_helper.py @@ -1,19 +1,20 @@ # Copyright 2020 InterDigital Communications, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); +# Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, +# distributed under the License is distributed on an 'AS IS' BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import enum import struct + from pathlib import Path @@ -23,46 +24,83 @@ def filesize(filepath: str) -> int: return Path(filepath).stat().st_size -def write_uints(fd, values, fmt=">{:d}I"): - fd.write(struct.pack(fmt.format(len(values)), *values)) - return len(values) * 4 +def read_bytes(fd, n, fmt='>{:d}s'): + sz = struct.calcsize('s') + return struct.unpack(fmt.format(n), fd.read(n * sz))[0] -def write_uchars(fd, values, fmt=">{:d}B"): - fd.write(struct.pack(fmt.format(len(values)), *values)) - return len(values) +def read_uchars(fd, n, fmt='>{:d}B'): + sz = struct.calcsize('B') + return struct.unpack(fmt.format(n), fd.read(n * sz)) -def read_uints(fd, n, fmt=">{:d}I"): - sz = struct.calcsize("I") - return struct.unpack(fmt.format(n), fd.read(n * sz)) +def read_header(f): + header = {} + flag = read_uchars(f, 1)[0] + nal_type = flag >> 4 + header['nal_type'] = NalType(nal_type) + if nal_type < 3: + header['sps_id'] = flag & 0x0f + return header + + frame_num_minus1 = flag & 0x0f + frame_num = frame_num_minus1 + 1 + header['frame_num'] = frame_num + sps_ids = [] + for _ in range(0, frame_num, 2): + flag = read_uchars(f, 1)[0] + sps_ids.append(flag >> 4) + sps_ids.append(flag & 0x0f) + sps_ids = sps_ids[:frame_num] + header['sps_ids'] = sps_ids + return header -def read_uchars(fd, n, fmt=">{:d}B"): - sz = struct.calcsize("B") - return struct.unpack(fmt.format(n), fd.read(n * sz)) +def read_uint_adaptive(f): + a3 = read_uchars(f, 1)[0] + if (a3 >> 7) == 0: + return a3 + + a2 = read_uchars(f, 1)[0] + + if (a3 >> 6) == 0x02: + a3 = a3 & 0x3f + return (a3 << 8) + a2 + a3 = a3 & 0x3f + a1 = read_uchars(f, 1)[0] + a0 = read_uchars(f, 1)[0] + return (a3 << 24) + (a2 << 16) + (a1 << 8) + a0 + + +def read_ip_remaining(f): + flag = read_uchars(f, 1)[0] + qp = flag + flag = read_uchars(f, 1)[0] + ec_part = (flag >> 1) & 0x7f + reset_feature_memory = flag & 0x01 + stream_length = read_uint_adaptive(f) + bit_stream = read_bytes(f, stream_length) + return qp, ec_part, reset_feature_memory, bit_stream + + +def read_sps_remaining(f, sps_id): + sps = {} + sps['sps_id'] = sps_id + sps['height'] = read_uint_adaptive(f) + sps['width'] = read_uint_adaptive(f) + return sps -def write_bytes(fd, values, fmt=">{:d}s"): +def write_bytes(fd, values, fmt='>{:d}s'): if len(values) == 0: return 0 fd.write(struct.pack(fmt.format(len(values)), values)) return len(values) -def read_bytes(fd, n, fmt=">{:d}s"): - sz = struct.calcsize("s") - return struct.unpack(fmt.format(n), fd.read(n * sz))[0] - - -def write_ushorts(fd, values, fmt=">{:d}H"): +def write_uchars(fd, values, fmt='>{:d}B'): fd.write(struct.pack(fmt.format(len(values)), *values)) - return len(values) * 2 - - -def read_ushorts(fd, n, fmt=">{:d}H"): - sz = struct.calcsize("H") - return struct.unpack(fmt.format(n), fd.read(n * sz)) + return len(values) def write_uint_adaptive(f, a): @@ -89,20 +127,31 @@ def write_uint_adaptive(f, a): return 4 -def read_uint_adaptive(f): - a3 = read_uchars(f, 1)[0] - if (a3 >> 7) == 0: - return a3 +def write_ip(f, is_i_frame, sps_id, qp, ec_part, reset_feature_memory, bit_stream): + written = 0 + flag = (int(NalType.NAL_I if is_i_frame else NalType.NAL_P) << 4) + sps_id + written += write_uchars(f, (flag,)) + assert 0 <= qp < 256 + written += write_uchars(f, (qp,)) + # ec_part(7), reset_feature_memory(1) + flag = (ec_part << 1) + reset_feature_memory + written += write_uchars(f, (flag,)) + written += write_uint_adaptive(f, len(bit_stream)) + written += write_bytes(f, bit_stream) + return written - a2 = read_uchars(f, 1)[0] - if (a3 >> 6) == 0x02: - a3 = a3 & 0x3f - return (a3 << 8) + a2 - a3 = a3 & 0x3f - a1 = read_uchars(f, 1)[0] - a0 = read_uchars(f, 1)[0] - return (a3 << 24) + (a2 << 16) + (a1 << 8) + a0 +def write_sps(f, sps): + # nal_type(4), sps_id(4) + # height (variable) + # width (variable) + assert sps['sps_id'] < 16 + written = 0 + flag = int((NalType.NAL_SPS << 4) + sps['sps_id']) + written += write_uchars(f, (flag,)) + written += write_uint_adaptive(f, sps['height']) + written += write_uint_adaptive(f, sps['width']) + return written class NalType(enum.IntEnum): @@ -116,24 +165,9 @@ def __init__(self): super().__init__() self.spss = [] - def get_sps_id(self, target_sps): - min_id = -1 - for sps in self.spss: - if sps['height'] == target_sps['height'] and sps['width'] == target_sps['width'] and \ - sps['use_ada_i'] == target_sps['use_ada_i'] and \ - sps['ec_part'] == target_sps['ec_part']: - return sps['sps_id'], False - if sps['sps_id'] > min_id: - min_id = sps['sps_id'] - assert min_id < 15 - sps = target_sps.copy() - sps['sps_id'] = min_id + 1 - self.spss.append(sps) - return sps['sps_id'], True - def add_sps_by_id(self, sps): - for i in range(len(self.spss)): - if self.spss[i]['sps_id'] == sps['sps_id']: + for i, existing_sps in enumerate(self.spss): + if existing_sps['sps_id'] == sps['sps_id']: self.spss[i] = sps.copy() return self.spss.append(sps.copy()) @@ -144,74 +178,15 @@ def get_sps_by_id(self, sps_id): return sps return None - -def write_sps(f, sps): - # nal_type(4), sps_id(4) - # height (variable) - # width (vairable) - # 0(6), ec_part(1) use_ada_i(1) - assert sps['sps_id'] < 16 - assert sps['use_ada_i'] < 2 - written = 0 - flag = int((NalType.NAL_SPS << 4) + sps['sps_id']) - written += write_uchars(f, (flag,)) - written += write_uint_adaptive(f, sps['height']) - written += write_uint_adaptive(f, sps['width']) - flag = (sps['ec_part'] << 2) + sps['use_ada_i'] - written += write_uchars(f, (flag,)) - return written - - -def read_header(f): - header = {} - flag = read_uchars(f, 1)[0] - nal_type = flag >> 4 - header['nal_type'] = NalType(nal_type) - if nal_type < 3: - header['sps_id'] = flag & 0x0f - return header - - frame_num_minus1 = flag & 0x0f - frame_num = frame_num_minus1 + 1 - header['frame_num'] = frame_num - sps_ids = [] - for _ in range(0, frame_num, 2): - flag = read_uchars(f, 1)[0] - sps_ids.append(flag >> 4) - sps_ids.append(flag & 0x0f) - sps_ids = sps_ids[:frame_num] - header['sps_ids'] = sps_ids - return header - - -def read_sps_remaining(f, sps_id): - sps = {} - sps['sps_id'] = sps_id - sps['height'] = read_uint_adaptive(f) - sps['width'] = read_uint_adaptive(f) - flag = read_uchars(f, 1)[0] - sps['ec_part'] = (flag >> 2) & 0x01 - sps['use_ada_i'] = flag & 0x01 - return sps - - -def write_ip(f, is_i_frame, sps_id, qp, bit_stream): - written = 0 - flag = (int(NalType.NAL_I if is_i_frame else NalType.NAL_P) << 4) + sps_id - written += write_uchars(f, (flag,)) - assert qp < 256 and qp >= 0 - flag = qp - written += write_uchars(f, (flag,)) - # we write all the streams in the same file, thus, we need to write the per-frame length - # if packed independently, we do not need to write it - written += write_uint_adaptive(f, len(bit_stream)) - written += write_bytes(f, bit_stream) - return written - - -def read_ip_remaining(f): - flag = read_uchars(f, 1)[0] - qp = flag - stream_length = read_uint_adaptive(f) - bit_stream = read_bytes(f, stream_length) - return qp, bit_stream + def get_sps_id(self, target_sps): + min_id = -1 + for sps in self.spss: + if sps['height'] == target_sps['height'] and sps['width'] == target_sps['width']: + return sps['sps_id'], False + if sps['sps_id'] > min_id: + min_id = sps['sps_id'] + assert min_id < 15 + sps = target_sps.copy() + sps['sps_id'] = min_id + 1 + self.spss.append(sps) + return sps['sps_id'], True diff --git a/src/utils/transforms.py b/src/utils/transforms.py index 9b96d17..271d075 100644 --- a/src/utils/transforms.py +++ b/src/utils/transforms.py @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + import numpy as np import scipy.ndimage import torch @@ -6,22 +9,9 @@ YCBCR_WEIGHTS = { # Spec: (K_r, K_g, K_b) with K_g = 1 - K_r - K_b - "ITU-R_BT.709": (0.2126, 0.7152, 0.0722) + 'ITU-R_BT.709': (0.2126, 0.7152, 0.0722) } - - -def ycbcr420_to_444_np(y, uv, order=0, separate=False): - ''' - y is 1xhxw Y float numpy array - uv is 2x(h/2)x(w/2) UV float numpy array - order: 0 nearest neighbor (default), 1: binear - return value is 3xhxw YCbCr float numpy array - ''' - uv = scipy.ndimage.zoom(uv, (1, 2, 2), order=order) - if separate: - return y, uv - yuv = np.concatenate((y, uv), axis=0) - return yuv +Kr, Kg, Kb = YCBCR_WEIGHTS['ITU-R_BT.709'] def rgb2ycbcr(rgb, is_bgr=False): @@ -29,7 +19,6 @@ def rgb2ycbcr(rgb, is_bgr=False): b, g, r = rgb.chunk(3, -3) else: r, g, b = rgb.chunk(3, -3) - Kr, Kg, Kb = YCBCR_WEIGHTS["ITU-R_BT.709"] y = Kr * r + Kg * g + Kb * b cb = 0.5 * (b - y) / (1 - Kb) + 0.5 cr = 0.5 * (r - y) / (1 - Kr) + 0.5 @@ -38,9 +27,33 @@ def rgb2ycbcr(rgb, is_bgr=False): return ycbcr +def rgb2ycbcr_np(rgb, quant=False): + ''' + Note: channel_last memory format + input is hxwx3 RGB float numpy array + output is ycbcr: hxwx3 + ''' + h, w, c = rgb.shape + assert c == 3 + assert h % 2 == 0 + assert w % 2 == 0 + r, g, b = np.split(rgb, 3, axis=2) + y = Kr * r + Kg * g + Kb * b + cb = 0.5 * (b - y) / (1 - Kb) + 0.5 + cr = 0.5 * (r - y) / (1 - Kr) + 0.5 + ycbcr = np.concatenate((y, cb, cr), axis=2) + ycbcr = np.clip(ycbcr, 0., 1.) + + if quant: + ycbcr = np.round(ycbcr * 255.) / 255. + + return ycbcr + + def ycbcr2rgb(ycbcr, is_bgr=False, clamp=True): + dtype = ycbcr.dtype + ycbcr = ycbcr.float() y, cb, cr = ycbcr.chunk(3, -3) - Kr, Kg, Kb = YCBCR_WEIGHTS["ITU-R_BT.709"] r = y + (2 - 2 * Kr) * (cr - 0.5) b = y + (2 - 2 * Kb) * (cb - 0.5) g = (y - Kr * r - Kb * b) / Kg @@ -50,7 +63,21 @@ def ycbcr2rgb(ycbcr, is_bgr=False, clamp=True): rgb = torch.cat((r, g, b), dim=-3) if clamp: rgb = torch.clamp(rgb, 0., 1.) - return rgb + return rgb.to(dtype) + + +def ycbcr420_to_444_np(y, uv, order=0, separate=False): + ''' + y is 1xhxw Y float numpy array + uv is 2x(h/2)x(w/2) UV float numpy array + order: 0 nearest neighbor (default), 1: binear + return value is 3xhxw YCbCr float numpy array + ''' + uv = scipy.ndimage.zoom(uv, (1, 2, 2), order=order) + if separate: + return y, uv + yuv = np.concatenate((y, uv), axis=0) + return yuv def yuv_444_to_420(yuv): diff --git a/src/utils/video_reader.py b/src/utils/video_reader.py index a251845..d17054c 100644 --- a/src/utils/video_reader.py +++ b/src/utils/video_reader.py @@ -1,9 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +import numpy as np import os -import numpy as np from PIL import Image @@ -28,7 +28,7 @@ def read_one_frame(self): return None png_path = os.path.join(self.src_path, - f"im{str(self.current_frame_index).zfill(self.padding)}.png" + f'im{str(self.current_frame_index).zfill(self.padding)}.png' ) if not os.path.exists(png_path): self.eof = True @@ -60,9 +60,7 @@ def __init__(self, src_path, width, height, skip_frame=0): self.uv_size = width * height // 2 self.uv_width = width // 2 self.uv_height = height // 2 - # pylint: disable=R1732 - self.file = open(src_path, "rb") - # pylint: enable=R1732 + self.file = open(src_path, 'rb') skipped_frame = 0 while not self.eof and skipped_frame < skip_frame: y = self.file.read(self.y_size) @@ -86,5 +84,16 @@ def read_one_frame(self): return y, uv + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + return False + + def __del__(self): + self.close() + def close(self): - self.file.close() + if self.file and not self.file.closed: + self.file.close() diff --git a/src/utils/video_writer.py b/src/utils/video_writer.py index d61089d..7d5f01a 100644 --- a/src/utils/video_writer.py +++ b/src/utils/video_writer.py @@ -20,7 +20,7 @@ def write_one_frame(self, rgb): rgb = rgb.transpose(1, 2, 0) png_path = os.path.join(self.dst_path, - f"im{str(self.current_frame_index).zfill(self.padding)}.png" + f'im{str(self.current_frame_index).zfill(self.padding)}.png' ) Image.fromarray(rgb).save(png_path) @@ -38,9 +38,7 @@ def __init__(self, dst_path, width, height): self.width = width self.height = height - # pylint: disable=R1732 - self.file = open(dst_path, "wb") - # pylint: enable=R1732 + self.file = open(dst_path, 'wb') def write_one_frame(self, y, uv): # y: 1xhxw uint8 numpy array @@ -48,5 +46,16 @@ def write_one_frame(self, y, uv): self.file.write(y.tobytes()) self.file.write(uv.tobytes()) + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + return False + + def __del__(self): + self.close() + def close(self): - self.file.close() + if self.file and not self.file.closed: + self.file.close() diff --git a/test_cfg/all_RGB.json b/test_cfg/all_RGB.json new file mode 100644 index 0000000..77b5bea --- /dev/null +++ b/test_cfg/all_RGB.json @@ -0,0 +1,100 @@ +{ + "root_path": "/data/test_sequences/PNG_BT709/", + "test_classes": { + "UVG": { + "test": 1, + "base_path": "UVG", + "src_type": "png", + "sequences": { + "Beauty_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "Bosphorus_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "HoneyBee_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "Jockey_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "ShakeNDry_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 300, "intra_period": -1}, + "YachtRide_1920x1080_120fps_420_8bit_YUV": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1} + } + }, + "MCL-JCV": { + "test": 1, + "base_path": "MCL-JCV", + "src_type": "png", + "sequences": { + "videoSRC01_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC02_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC03_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC04_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC05_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC06_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC07_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC08_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC09_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC10_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC11_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC12_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC13_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC14_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC15_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC16_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC17_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC18_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC19_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC20_1920x1080_25": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC21_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC22_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC23_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC24_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC25_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC26_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC27_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC28_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC29_1920x1080_24": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC30_1920x1080_30": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1} + } + }, + "HEVC_B": { + "test": 1, + "base_path": "HEVC_B", + "src_type": "png", + "sequences": { + "BQTerrace_1920x1080_60": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "BasketballDrive_1920x1080_50": {"width": 1920, "height": 1080, "frames": 500, "intra_period": -1}, + "Cactus_1920x1080_50": {"width": 1920, "height": 1080, "frames": 500, "intra_period": -1}, + "Kimono1_1920x1080_24": {"width": 1920, "height": 1080, "frames": 240, "intra_period": -1}, + "ParkScene_1920x1080_24": {"width": 1920, "height": 1080, "frames": 240, "intra_period": -1} + } + }, + "HEVC_E": { + "test": 1, + "base_path": "HEVC_E", + "src_type": "png", + "sequences": { + "FourPeople_1280x720_60": {"width": 1280, "height": 720, "frames": 600, "intra_period": -1}, + "Johnny_1280x720_60": {"width": 1280, "height": 720, "frames": 600, "intra_period": -1}, + "KristenAndSara_1280x720_60": {"width": 1280, "height": 720, "frames": 600, "intra_period": -1} + } + }, + "HEVC_C": { + "test": 1, + "base_path": "HEVC_C", + "src_type": "png", + "sequences": { + "BQMall_832x480_60": {"width": 832, "height": 480, "frames": 600, "intra_period": -1}, + "BasketballDrill_832x480_50": {"width": 832, "height": 480, "frames": 500, "intra_period": -1}, + "PartyScene_832x480_50": {"width": 832, "height": 480, "frames": 500, "intra_period": -1}, + "RaceHorses_832x480_30": {"width": 832, "height": 480, "frames": 300, "intra_period": -1} + } + }, + "HEVC_D": { + "test": 1, + "base_path": "HEVC_D", + "src_type": "png", + "sequences": { + "BasketballPass_416x240_50": {"width": 416, "height": 240, "frames": 500, "intra_period": -1}, + "BlowingBubbles_416x240_50": {"width": 416, "height": 240, "frames": 500, "intra_period": -1}, + "BQSquare_416x240_60": {"width": 416, "height": 240, "frames": 600, "intra_period": -1}, + "RaceHorses_416x240_30": {"width": 416, "height": 240, "frames": 300, "intra_period": -1} + } + } + } +} diff --git a/test_cfg/all_yuv420.json b/test_cfg/all_yuv420.json new file mode 100644 index 0000000..f03cb97 --- /dev/null +++ b/test_cfg/all_yuv420.json @@ -0,0 +1,100 @@ +{ + "root_path": "/data/test_sequences/YUV/", + "test_classes": { + "UVG": { + "test": 1, + "base_path": "UVG", + "src_type": "yuv420", + "sequences": { + "Beauty_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "Bosphorus_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "HoneyBee_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "Jockey_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "ReadySteadyGo_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "ShakeNDry_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 300, "intra_period": -1}, + "YachtRide_1920x1080_120fps_420_8bit_YUV.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1} + } + }, + "MCL-JCV": { + "test": 1, + "base_path": "MCL-JCV", + "src_type": "yuv420", + "sequences": { + "videoSRC01_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC02_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC03_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC04_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC05_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC06_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC07_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC08_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC09_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC10_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC11_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC12_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC13_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC14_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC15_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC16_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC17_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC18_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC19_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC20_1920x1080_25.yuv": {"width": 1920, "height": 1080, "frames": 125, "intra_period": -1}, + "videoSRC21_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC22_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC23_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC24_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC25_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC26_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC27_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC28_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1}, + "videoSRC29_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 120, "intra_period": -1}, + "videoSRC30_1920x1080_30.yuv": {"width": 1920, "height": 1080, "frames": 150, "intra_period": -1} + } + }, + "HEVC_B": { + "test": 1, + "base_path": "HEVC_B", + "src_type": "yuv420", + "sequences": { + "BQTerrace_1920x1080_60.yuv": {"width": 1920, "height": 1080, "frames": 600, "intra_period": -1}, + "BasketballDrive_1920x1080_50.yuv": {"width": 1920, "height": 1080, "frames": 500, "intra_period": -1}, + "Cactus_1920x1080_50.yuv": {"width": 1920, "height": 1080, "frames": 500, "intra_period": -1}, + "Kimono1_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 240, "intra_period": -1}, + "ParkScene_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 240, "intra_period": -1} + } + }, + "HEVC_E": { + "test": 1, + "base_path": "HEVC_E", + "src_type": "yuv420", + "sequences": { + "FourPeople_1280x720_60.yuv": {"width": 1280, "height": 720, "frames": 600, "intra_period": -1}, + "Johnny_1280x720_60.yuv": {"width": 1280, "height": 720, "frames": 600, "intra_period": -1}, + "KristenAndSara_1280x720_60.yuv": {"width": 1280, "height": 720, "frames": 600, "intra_period": -1} + } + }, + "HEVC_C": { + "test": 1, + "base_path": "HEVC_C", + "src_type": "yuv420", + "sequences": { + "BQMall_832x480_60.yuv": {"width": 832, "height": 480, "frames": 600, "intra_period": -1}, + "BasketballDrill_832x480_50.yuv": {"width": 832, "height": 480, "frames": 500, "intra_period": -1}, + "PartyScene_832x480_50.yuv": {"width": 832, "height": 480, "frames": 500, "intra_period": -1}, + "RaceHorses_832x480_30.yuv": {"width": 832, "height": 480, "frames": 300, "intra_period": -1} + } + }, + "HEVC_D": { + "test": 1, + "base_path": "HEVC_D", + "src_type": "yuv420", + "sequences": { + "BasketballPass_416x240_50.yuv": {"width": 416, "height": 240, "frames": 500, "intra_period": -1}, + "BlowingBubbles_416x240_50.yuv": {"width": 416, "height": 240, "frames": 500, "intra_period": -1}, + "BQSquare_416x240_60.yuv": {"width": 416, "height": 240, "frames": 600, "intra_period": -1}, + "RaceHorses_416x240_30.yuv": {"width": 416, "height": 240, "frames": 300, "intra_period": -1} + } + } + } +} diff --git a/test_cfg/runtime_avg.json b/test_cfg/runtime_avg.json new file mode 100644 index 0000000..27da9df --- /dev/null +++ b/test_cfg/runtime_avg.json @@ -0,0 +1,17 @@ +{ + "root_path": "/data/test_sequences/YUV/", + "test_classes": { + "HEVC_B": { + "test": 1, + "base_path": "HEVC_B", + "src_type": "yuv420", + "sequences": { + "BQTerrace_1920x1080_60.yuv": {"width": 1920, "height": 1080, "frames": 97, "intra_period": -1}, + "BasketballDrive_1920x1080_50.yuv": {"width": 1920, "height": 1080, "frames": 97, "intra_period": -1}, + "Cactus_1920x1080_50.yuv": {"width": 1920, "height": 1080, "frames": 97, "intra_period": -1}, + "Kimono1_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 97, "intra_period": -1}, + "ParkScene_1920x1080_24.yuv": {"width": 1920, "height": 1080, "frames": 97, "intra_period": -1} + } + } + } +} diff --git a/test_compress_time.py b/test_compress_time.py new file mode 100644 index 0000000..cb1646c --- /dev/null +++ b/test_compress_time.py @@ -0,0 +1,73 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import argparse +import json +import os +import sys + + +def parse_args(argv): + parser = argparse.ArgumentParser() + + parser.add_argument('--img', action='store_true', help='test image codec') + parser.add_argument('--model_structure', type=str, default='ld', choices=['htl', 'hts', 'ld'], + help='model structure to test') + parser.add_argument('--output_path', type=str, default='temp.json') + + args = parser.parse_args(argv) + + return args + + +def main(argv): + args = parse_args(argv) + + model_path_i = 'checkpoints/cvpr2026_image.pth.tar' + model_path_p = f'checkpoints/cvpr2026_video_{args.model_structure}.pth.tar' + + dataset = 'HEVC_B' + benchmark_config = 'test_cfg/runtime_avg.json' + + if args.img: + img_arg = ' --force_intra 1' + else: + img_arg = ' --force_intra 0' + + command_line = (f' python test_video.py --verbose 2 --rate_num 4 {img_arg}' + f' --test_config {benchmark_config}' + f' --force_frame_num -1' + f' --cuda_idx 0 -w 1' + ' --skip_thres 0.15' + f' --output_path {args.output_path}' + f' --model_path_i {model_path_i}' + f' --model_path_p {model_path_p}' + f' --model_structure {args.model_structure}') + + print(command_line, flush=True) + os.system(command_line) + + res = json.load(open(args.output_path, 'r')) + res = res[dataset] + encoding_time = [] + decoding_time = [] + for seq in res: + for qp in res[seq]: + enc_t = res[seq][qp]['avg_frame_encoding_time'] + dec_t = res[seq][qp]['avg_frame_decoding_time'] + encoding_time.append(enc_t) + decoding_time.append(dec_t) + avg_encoding_time = sum(encoding_time) / len(encoding_time) + avg_decoding_time = sum(decoding_time) / len(decoding_time) + if args.model_structure == 'ld': + from src.models.video_model_ld import g_frame_delay as frame_delay + else: + from src.models.video_model_ht import g_frame_delay as frame_delay + print(f'Average encoding time on {dataset}' + f' = {avg_encoding_time * 1000:.4f} ms / {frame_delay / avg_encoding_time:.4f} fps') + print(f'Average decoding time on {dataset}' + f' = {avg_decoding_time * 1000:.4f} ms / {frame_delay / avg_decoding_time:.4f} fps') + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/test_video.py b/test_video.py index 8658569..9f8ce7b 100644 --- a/test_video.py +++ b/test_video.py @@ -6,92 +6,31 @@ import io import json import multiprocessing +import numpy as np import os import time - import torch -import numpy as np + from tqdm import tqdm -from src.layers.cuda_inference import replicate_pad -from src.models.video_model import DMC from src.models.image_model import DMCI -from src.utils.common import str2bool, create_folder, generate_log_json, get_state_dict, \ - dump_json, set_torch_env +from src.utils.common import ModelStructure, str2bool, create_folder, generate_log_json, \ + get_state_dict, dump_json, set_torch_env +from src.utils.metrics import calc_msssim, calc_msssim_rgb, calc_psnr from src.utils.stream_helper import SPSHelper, NalType, write_sps, read_header, \ read_sps_remaining, read_ip_remaining, write_ip +from src.utils.transforms import rgb2ycbcr, ycbcr2rgb, yuv_444_to_420, ycbcr420_to_444_np from src.utils.video_reader import PNGReader, YUV420Reader from src.utils.video_writer import PNGWriter, YUV420Writer -from src.utils.metrics import calc_psnr, calc_msssim, calc_msssim_rgb -from src.utils.transforms import rgb2ycbcr, ycbcr2rgb, yuv_444_to_420, ycbcr420_to_444_np -def parse_args(): - parser = argparse.ArgumentParser(description="Example testing script") - - parser.add_argument('--force_zero_thres', type=float, default=None, required=False) - parser.add_argument('--model_path_i', type=str) - parser.add_argument('--model_path_p', type=str) - parser.add_argument('--rate_num', type=int, default=4) - parser.add_argument('--qp_i', type=int, nargs="+") - parser.add_argument('--qp_p', type=int, nargs="+") - parser.add_argument("--force_intra", type=str2bool, default=False) - parser.add_argument("--force_frame_num", type=int, default=-1) - parser.add_argument("--force_intra_period", type=int, default=-1) - parser.add_argument('--reset_interval', type=int, default=32, required=False) - parser.add_argument('--test_config', type=str, required=True) - parser.add_argument('--force_root_path', type=str, default=None, required=False) - parser.add_argument("--worker", "-w", type=int, default=1, help="worker number") - parser.add_argument("--cuda", type=str2bool, default=False) - parser.add_argument('--cuda_idx', type=int, nargs="+", help='GPU indexes to use') - parser.add_argument('--calc_ssim', type=str2bool, default=False, required=False) - parser.add_argument('--write_stream', type=str2bool, default=False) - parser.add_argument('--check_existing', type=str2bool, default=False) - parser.add_argument('--stream_path', type=str, default="out_bin") - parser.add_argument('--save_decoded_frame', type=str2bool, default=False) - parser.add_argument('--output_path', type=str, required=True) - parser.add_argument('--verbose_json', type=str2bool, default=False) - parser.add_argument('--verbose', type=int, default=0) - - args = parser.parse_args() - return args - - -def np_image_to_tensor(img, device): - image = torch.from_numpy(img).to(device=device).to(dtype=torch.float32) / 255.0 - image = image.unsqueeze(0) - return image - - -def get_src_reader(args): - if args['src_type'] == 'png': - src_reader = PNGReader(args['src_path'], args['src_width'], args['src_height']) - elif args['src_type'] == 'yuv420': - src_reader = YUV420Reader(args['src_path'], args['src_width'], args['src_height']) - return src_reader - - -def get_src_frame(args, src_reader, device): - if args['src_type'] == 'yuv420': - y, uv = src_reader.read_one_frame() - yuv = ycbcr420_to_444_np(y, uv) - x = np_image_to_tensor(yuv, device) - y = y[0, :, :] - u = uv[0, :, :] - v = uv[1, :, :] - rgb = None - else: - assert args['src_type'] == 'png' - rgb = src_reader.read_one_frame() - x = np_image_to_tensor(rgb, device) - x = rgb2ycbcr(x) - y, u, v = None, None, None - - x = x.to(torch.float16) - return x, y, u, v, rgb +def finalize_model(net, device): + net = net.half().to(device) + return net.to(memory_format=torch.channels_last) def get_distortion(args, x_hat, y, u, v, rgb): + x_hat = x_hat + 0.5 if args['src_type'] == 'yuv420': y_rec, uv_rec = yuv_444_to_420(x_hat) y_rec = torch.clamp(y_rec * 255, 0, 255).squeeze(0).cpu().numpy() @@ -127,14 +66,112 @@ def get_distortion(args, x_hat, y, u, v, rgb): return curr_psnr, curr_ssim -def run_one_point_with_stream(p_frame_net, i_frame_net, args): +def get_src_frame(args, src_reader, device, maximum_read, is_intra, np_only=False): + if args['src_type'] == 'yuv420': + processed = 0 + x, y, u, v, rgb = [], [], [], [], [] + while processed < maximum_read: + curr_y, curr_uv = src_reader.read_one_frame() + curr_yuv = ycbcr420_to_444_np(curr_y, curr_uv) + curr_x = torch.from_numpy(curr_yuv).unsqueeze(0) + curr_y = curr_y[0, :, :] + curr_u = curr_uv[0, :, :] + curr_v = curr_uv[1, :, :] + curr_rgb = None + x.append(curr_x) + y.append(curr_y) + u.append(curr_u) + v.append(curr_v) + rgb.append(curr_rgb) + processed += 1 + else: + assert args['src_type'] == 'png' + processed = 0 + x, y, u, v, rgb = [], [], [], [], [] + while processed < maximum_read: + curr_rgb = src_reader.read_one_frame() + curr_x = torch.from_numpy(curr_rgb).unsqueeze(0).to(device=device, non_blocking=True) + curr_x = curr_x.float() / 255.0 + curr_x = rgb2ycbcr(curr_x) + curr_y, curr_u, curr_v = None, None, None + x.append(curr_x) + y.append(curr_y) + u.append(curr_u) + v.append(curr_v) + rgb.append(curr_rgb) + processed += 1 + + while not is_intra and processed < g_frame_delay: + x.append(x[-1]) + y.append(y[-1]) + u.append(u[-1]) + v.append(v[-1]) + rgb.append(rgb[-1]) + processed += 1 + + if np_only: + return y, u, v, rgb + + x = torch.cat(x, dim=1) + if args['src_type'] == 'yuv420': + x = x.to(device=device, non_blocking=True) + x = x.half() + if args['src_type'] == 'yuv420': + x = x / 255.0 + x = x - 0.5 + x = x.to(memory_format=torch.channels_last) + return x, y, u, v, rgb + + +def get_src_reader(args): + if args['src_type'] == 'png': + src_reader = PNGReader(args['src_path'], args['src_width'], args['src_height']) + elif args['src_type'] == 'yuv420': + src_reader = YUV420Reader(args['src_path'], args['src_width'], args['src_height']) + else: + assert False + return src_reader + + +def parse_args(): + parser = argparse.ArgumentParser() + + parser.add_argument('--skip_thres', type=float, default=0) + parser.add_argument('--model_path_i', type=str) + parser.add_argument('--model_path_p', type=str) + parser.add_argument('--rate_num', type=int, default=4) + parser.add_argument('--qp_i', type=int, nargs='+') + parser.add_argument('--qp_p', type=int, nargs='+') + parser.add_argument('--force_intra', type=str2bool, default=False) + parser.add_argument('--force_frame_num', type=int, default=-1) + parser.add_argument('--force_intra_period', type=int, default=-1) + parser.add_argument('--reset_interval', type=int, default=32) + parser.add_argument('--test_config', type=str, required=True) + parser.add_argument('--force_root_path', type=str, default=None, required=False) + parser.add_argument('--worker', '-w', type=int, default=1, help='worker number') + parser.add_argument('--model_structure', type=str, default='ld', choices=['htl', 'hts', 'ld']) + parser.add_argument('--cuda_idx', type=int, nargs='+', help='GPU indexes to use') + parser.add_argument('--calc_ssim', type=str2bool, default=False, required=False) + parser.add_argument('--check_existing', type=str2bool, default=False) + parser.add_argument('--stream_path', type=str, default='out_bin') + parser.add_argument('--save_decoded_frame', type=str2bool, default=False) + parser.add_argument('--output_path', type=str, required=True) + parser.add_argument('--verbose_json', type=str2bool, default=False) + parser.add_argument('--verbose', type=int, default=0) + + args = parser.parse_args() + return args + + +@torch.inference_mode() +def run_one_point_with_stream(p_net, i_net, args): if args['check_existing'] and os.path.exists(args['curr_json_path']) and \ os.path.exists(args['curr_bin_path']): with open(args['curr_json_path']) as f: log_result = json.load(f) if log_result['i_frame_num'] + log_result['p_frame_num'] == args['frame_num']: return log_result - print(f"incorrect log for {args['curr_json_path']}, try to rerun.") + print(f'incorrect log for {args['curr_json_path']}, try to rerun.') frame_num = args['frame_num'] save_decoded_frame = args['save_decoded_frame'] @@ -142,99 +179,99 @@ def run_one_point_with_stream(p_frame_net, i_frame_net, args): reset_interval = args['reset_interval'] intra_period = args['intra_period'] verbose_json = args['verbose_json'] - device = next(i_frame_net.parameters()).device + device = next(i_net.parameters()).device src_reader = get_src_reader(args) pic_height = args['src_height'] pic_width = args['src_width'] padding_r, padding_b = DMCI.get_padding_size(pic_height, pic_width, 16) - use_two_entropy_coders = pic_height * pic_width > 1280 * 720 - i_frame_net.set_use_two_entropy_coders(use_two_entropy_coders) - p_frame_net.set_use_two_entropy_coders(use_two_entropy_coders) - frame_types = [] psnrs = [] msssims = [] bits = [] + start_event = torch.cuda.Event(enable_timing=True) + end_event = torch.cuda.Event(enable_timing=True) + start_time = time.time() encoding_time = [] decoding_time = [] - index_map = [0, 1, 0, 2, 0, 2, 0, 2] output_buff = io.BytesIO() sps_helper = SPSHelper() - p_frame_net.set_curr_poc(0) - with torch.no_grad(): - last_qp = 0 - for frame_idx in range(frame_num): - x, y, u, v, rgb = get_src_frame(args, src_reader, device) - - torch.cuda.synchronize(device=device) - frame_start_time = time.time() - - # pad if necessary - x_padded = replicate_pad(x, padding_b, padding_r) - - is_i_frame = False - if frame_idx == 0 or (intra_period > 0 and frame_idx % intra_period == 0): - is_i_frame = True - curr_qp = args['qp_i'] - sps = { - 'sps_id': -1, - 'height': pic_height, - 'width': pic_width, - 'ec_part': 1 if use_two_entropy_coders else 0, - 'use_ada_i': 0, - } - encoded = i_frame_net.compress(x_padded, args['qp_i']) - p_frame_net.clear_dpb() - p_frame_net.add_ref_frame(None, encoded['x_hat']) - frame_types.append(0) + frame_idx = 0 + while frame_idx < frame_num: + is_intra = False + if frame_idx == 0 or intra_period == 1: + is_intra = True + if intra_period > 1 and frame_idx != 1: + assert intra_period % g_frame_delay == 0 + if frame_idx % intra_period == 1: + is_intra = True + + maximum_read = min(g_frame_delay, frame_num - frame_idx) + if is_intra: + maximum_read = 1 + + x, y, u, v, rgb = get_src_frame(args, src_reader, device, maximum_read, is_intra) + + torch.cuda.synchronize(device=device) + start_event.record() + + if is_intra: + curr_qp = args['qp_i'] + reset_feature_memory = 0 + encoded = i_net.compress(x, curr_qp, padding_b, padding_r) + if not args['force_intra']: + p_net.clear_dpb() + p_net.add_ref_feature_from_frame(encoded['x_hat']) + frame_types.append(0) + else: + if reset_interval > 0 and (frame_idx + g_frame_delay) % reset_interval == 1: + reset_feature_memory = 1 else: - fa_idx = index_map[frame_idx % 8] - if reset_interval > 0 and frame_idx % reset_interval == 1: - use_ada_i = 1 - p_frame_net.prepare_feature_adaptor_i(last_qp) - else: - use_ada_i = 0 - curr_qp = p_frame_net.shift_qp(args['qp_p'], fa_idx) - sps = { - 'sps_id': -1, - 'height': pic_height, - 'width': pic_width, - 'ec_part': 1 if use_two_entropy_coders else 0, - 'use_ada_i': use_ada_i, - } - - encoded = p_frame_net.compress(x_padded, curr_qp) - last_qp = curr_qp + reset_feature_memory = 0 + curr_qp = args['qp_p'] + + encoded = p_net.compress(x, curr_qp, reset_feature_memory, padding_b, padding_r) + for _ in range(maximum_read): frame_types.append(1) - sps_id, sps_new = sps_helper.get_sps_id(sps) - sps['sps_id'] = sps_id - sps_bytes = 0 - if sps_new: - sps_bytes = write_sps(output_buff, sps) - if verbose >= 2: - print("new sps", sps) - stream_bytes = write_ip(output_buff, is_i_frame, sps_id, curr_qp, encoded['bit_stream']) - bits.append(stream_bytes * 8 + sps_bytes * 8) + sps = { + 'sps_id': -1, + 'height': pic_height, + 'width': pic_width, + } + sps_id, sps_new = sps_helper.get_sps_id(sps) + sps['sps_id'] = sps_id + sps_bytes = 0 + if sps_new: + sps_bytes = write_sps(output_buff, sps) + if verbose >= 2: + print('new sps', sps) + stream_bytes = write_ip(output_buff, is_intra, sps_id, curr_qp, + encoded['ec_parallel'], reset_feature_memory, + encoded['bit_stream']) + bits.append(stream_bytes * 8 + sps_bytes * 8) + for _ in range(1, maximum_read): + bits.append(0) + + end_event.record() + torch.cuda.synchronize(device=device) - torch.cuda.synchronize(device=device) - frame_end_time = time.time() + frame_time = start_event.elapsed_time(end_event) / 1000.0 + encoding_time.append(frame_time) - frame_time = frame_end_time - frame_start_time - encoding_time.append(frame_time) + if verbose >= 2: + print(f'frame {frame_idx} encoded, {frame_time * 1000:.3f} ms, ' + f'bits: {bits[-maximum_read]}') - if verbose >= 2: - print(f"frame {frame_idx} encoded, {frame_time * 1000:.3f} ms, " - f"bits: {bits[-1]}") + frame_idx += maximum_read src_reader.close() - with open(args['curr_bin_path'], "wb") as output_file: + with open(args['curr_bin_path'], 'wb') as output_file: bytes_buffer = output_buff.getbuffer() output_file.write(bytes_buffer) total_bytes = bytes_buffer.nbytes @@ -242,8 +279,7 @@ def run_one_point_with_stream(p_frame_net, i_frame_net, args): total_kbps = int(total_bytes * 8 / (frame_num / 30) / 1000) # assume 30 fps output_buff.close() sps_helper = SPSHelper() - input_file = open(args['curr_bin_path'], "rb") - with open(args['curr_bin_path'], "rb") as input_file: + with open(args['curr_bin_path'], 'rb') as input_file: input_buff = io.BytesIO(input_file.read()) decoded_frame_number = 0 src_reader = get_src_reader(args) @@ -255,68 +291,84 @@ def run_one_point_with_stream(p_frame_net, i_frame_net, args): output_yuv_path = args['curr_rec_path'].replace('.yuv', f'_{total_kbps}kbps.yuv') recon_writer = YUV420Writer(output_yuv_path, args['src_width'], args['src_height']) - p_frame_net.set_curr_poc(0) - with torch.no_grad(): - while decoded_frame_number < frame_num: - x, y, u, v, rgb = get_src_frame(args, src_reader, device) - torch.cuda.synchronize(device=device) - frame_start_time = time.time() + while decoded_frame_number < frame_num: + torch.cuda.synchronize(device=device) + start_event.record() + header = read_header(input_buff) + while header['nal_type'] == NalType.NAL_SPS: + sps = read_sps_remaining(input_buff, header['sps_id']) + sps_helper.add_sps_by_id(sps) + if verbose >= 2: + print('new sps', sps) header = read_header(input_buff) - while header['nal_type'] == NalType.NAL_SPS: - sps = read_sps_remaining(input_buff, header['sps_id']) - sps_helper.add_sps_by_id(sps) - if verbose >= 2: - print("new sps", sps) - header = read_header(input_buff) - continue - sps_id = header['sps_id'] - - sps = sps_helper.get_sps_by_id(sps_id) - qp, bit_stream = read_ip_remaining(input_buff) - - if header['nal_type'] == NalType.NAL_I: - decoded = i_frame_net.decompress(bit_stream, sps, qp) - p_frame_net.clear_dpb() - p_frame_net.add_ref_frame(None, decoded['x_hat']) - elif header['nal_type'] == NalType.NAL_P: - if sps['use_ada_i']: - p_frame_net.reset_ref_feature() - decoded = p_frame_net.decompress(bit_stream, sps, qp) - - recon_frame = decoded['x_hat'] - x_hat = recon_frame[:, :, :pic_height, :pic_width] - - torch.cuda.synchronize(device=device) - frame_end_time = time.time() - - frame_time = frame_end_time - frame_start_time - decoding_time.append(frame_time) - - curr_psnr, curr_ssim = get_distortion(args, x_hat, y, u, v, rgb) + continue + sps_id = header['sps_id'] + + sps = sps_helper.get_sps_by_id(sps_id) + qp, ec_part, reset_feature_memory, bit_stream = read_ip_remaining(input_buff) + + if header['nal_type'] == NalType.NAL_I: + decoded = i_net.decompress(bit_stream, sps, qp, ec_part) + if not args['force_intra']: + p_net.clear_dpb() + p_net.add_ref_feature_from_frame(decoded['x_hat'], apply_feature_adaptor=False) + elif header['nal_type'] == NalType.NAL_P: + decoded = p_net.decompress(bit_stream, sps, qp, ec_part, reset_feature_memory) + + recon_frame = decoded['x_hat'] + + end_event.record() + torch.cuda.synchronize(device=device) + + frame_time = start_event.elapsed_time(end_event) / 1000.0 + decoding_time.append(frame_time) + + is_intra = header['nal_type'] == NalType.NAL_I + maximum_read = min(g_frame_delay, frame_num - decoded_frame_number) + if is_intra: + maximum_read = 1 + y, u, v, rgb = get_src_frame(args, src_reader, device, maximum_read, is_intra, np_only=True) + + for i in range(maximum_read): + if isinstance(recon_frame, list): + x_hat = recon_frame[i] + else: + x_hat = recon_frame + x_hat = x_hat[:, :, :pic_height, :pic_width] + curr_psnr, curr_ssim = get_distortion(args, x_hat, y[i], u[i], v[i], rgb[i]) psnrs.append(curr_psnr) msssims.append(curr_ssim) - if verbose >= 2: - stream_length = 0 if bit_stream is None else len(bit_stream) * 8 - print(f"frame {decoded_frame_number} decoded, {frame_time * 1000:.3f} ms, " - f"bits: {stream_length}, PSNR: {curr_psnr[0]:.4f} ") - - if save_decoded_frame: + if verbose >= 2: + stream_length = 0 if bit_stream is None else len(bit_stream) * 8 + print(f'frame {decoded_frame_number} decoded, {frame_time * 1000:.3f} ms, ' + f'bits: {stream_length}, ', end='') + for i in range(-maximum_read, 0, 1): + print(f'PSNR: {psnrs[i][0]:.4f}, ', end='') + print() + + if save_decoded_frame: + for i in range(maximum_read): + if isinstance(recon_frame, list): + x_hat = recon_frame[i] + else: + x_hat = recon_frame + x_hat = x_hat[:, :, :pic_height, :pic_width] if args['src_type'] == 'yuv420': - y_rec, uv_rec = yuv_444_to_420(x_hat) - y_rec = torch.clamp(y_rec * 255, 0, 255).round().to(dtype=torch.uint8) + y_rec, uv_rec = yuv_444_to_420(x_hat + 0.5) + y_rec = torch.clamp(y_rec * 255, 0, 255).round().byte() y_rec = y_rec.squeeze(0).cpu().numpy() - uv_rec = torch.clamp(uv_rec * 255, 0, 255).to(dtype=torch.uint8) + uv_rec = torch.clamp(uv_rec * 255, 0, 255).byte() uv_rec = uv_rec.squeeze(0).cpu().numpy() recon_writer.write_one_frame(y_rec, uv_rec) else: assert args['src_type'] == 'png' - rgb_rec = ycbcr2rgb(x_hat) - rgb_rec = torch.clamp(rgb_rec * 255, 0, 255).round().to(dtype=torch.uint8) + rgb_rec = ycbcr2rgb(x_hat + 0.5) + rgb_rec = torch.clamp(rgb_rec * 255, 0, 255).round().byte() rgb_rec = rgb_rec.squeeze(0).cpu().numpy() recon_writer.write_one_frame(rgb_rec) - decoded_frame_number += 1 + decoded_frame_number += maximum_read input_buff.close() src_reader.close() @@ -325,15 +377,15 @@ def run_one_point_with_stream(p_frame_net, i_frame_net, args): test_time = time.time() - start_time test_time_frame_numuber = len(encoding_time) - time_bypass_frame_num = 10 # bypass the first 10 frames as warmup + time_bypass_frame_num = 4 # bypass the first 4 * g_frame_delay frames as warmup if verbose >= 1 and test_time_frame_numuber > time_bypass_frame_num: encoding_time = encoding_time[time_bypass_frame_num:] decoding_time = decoding_time[time_bypass_frame_num:] avg_encoding_time = sum(encoding_time)/len(encoding_time) avg_decoding_time = sum(decoding_time)/len(decoding_time) - print(f"encoding/decoding {test_time_frame_numuber} frames, " - f"average encoding time {avg_encoding_time * 1000:.3f} ms, " - f"average decoding time {avg_decoding_time * 1000:.3f} ms.") + print(f'encoding/decoding {len(encoding_time)} * {g_frame_delay} frames, ' + f'average encoding time {avg_encoding_time * 1000:.3f} ms, ' + f'average decoding time {avg_decoding_time * 1000:.3f} ms.') else: avg_encoding_time = None avg_decoding_time = None @@ -347,35 +399,9 @@ def run_one_point_with_stream(p_frame_net, i_frame_net, args): return log_result -i_frame_net = None # the model is initialized after each process is spawn, thus OK for multiprocess -p_frame_net = None - - -def worker(args): - global i_frame_net - global p_frame_net - - sub_dir_name = args['seq'] - bin_folder = os.path.join(args['stream_path'], args['ds_name']) - assert args['write_stream'], "" - create_folder(bin_folder, True) - - args['src_path'] = os.path.join(args['dataset_path'], sub_dir_name) - args['bin_folder'] = bin_folder - args['curr_bin_path'] = os.path.join(bin_folder, - f"{args['seq']}_q{args['qp_i']}.bin") - args['curr_rec_path'] = args['curr_bin_path'].replace('.bin', '.yuv') - args['curr_json_path'] = args['curr_bin_path'].replace('.bin', '.json') - - result = run_one_point_with_stream(p_frame_net, i_frame_net, args) - - result['ds_name'] = args['ds_name'] - result['seq'] = args['seq'] - result['rate_idx'] = args['rate_idx'] - result['qp_i'] = args['qp_i'] - result['qp_p'] = args['qp_p'] if 'qp_p' in args else args['qp_i'] - - return result +g_i_net = None # the model is initialized after each process is spawn, thus OK for multiprocess +g_p_net = None +g_frame_delay = None # depending on the model_structure (1 or 8) def init_func(args, gpu_num): @@ -390,28 +416,62 @@ def init_func(args, gpu_num): if args.cuda_idx is not None: gpu_id = args.cuda_idx[gpu_id] os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) - device = "cuda:0" + device = 'cuda:0' + else: + device = 'cpu' + + # one-time setup of default cuda stream. cuda graph does not support stream 0 + custom_stream = torch.cuda.Stream(device, 0) + torch.cuda.set_stream(custom_stream) + + model_structure = ModelStructure(args.model_structure) + + if model_structure == ModelStructure.LD: + from src.models.video_model_ld import DMC, g_frame_delay as frame_delay else: - device = "cpu" + from src.models.video_model_ht import DMC, g_frame_delay as frame_delay - global i_frame_net - i_frame_net = DMCI() + global g_i_net + g_i_net = DMCI() + g_i_net = g_i_net.eval() i_state_dict = get_state_dict(args.model_path_i) - i_frame_net.load_state_dict(i_state_dict) - i_frame_net = i_frame_net.to(device) - i_frame_net.eval() - i_frame_net.update(args.force_zero_thres) - i_frame_net.half() - - global p_frame_net - p_frame_net = DMC() + g_i_net.load_state_dict(i_state_dict) + g_i_net.update(args.skip_thres) + g_i_net = finalize_model(g_i_net, device) + if not args.force_intra: + global g_p_net + if model_structure == ModelStructure.LD: + g_p_net = DMC() + else: + g_p_net = DMC(model_structure=model_structure) + g_p_net = g_p_net.eval() p_state_dict = get_state_dict(args.model_path_p) - p_frame_net.load_state_dict(p_state_dict) - p_frame_net = p_frame_net.to(device) - p_frame_net.eval() - p_frame_net.update(args.force_zero_thres) - p_frame_net.half() + g_p_net.load_state_dict(p_state_dict) + g_p_net.update(args.skip_thres) + g_p_net = finalize_model(g_p_net, device) + + global g_frame_delay + g_frame_delay = frame_delay + + +def worker(args): + sub_dir_name = args['seq'] + bin_folder = os.path.join(args['stream_path'], args['ds_name']) + create_folder(bin_folder, True) + + args['src_path'] = os.path.join(args['dataset_path'], sub_dir_name) + args['bin_folder'] = bin_folder + args['curr_bin_path'] = os.path.join(bin_folder, f'{args['seq']}_q{args['qp_i']}.bin') + args['curr_rec_path'] = args['curr_bin_path'].replace('.bin', '.mp4') + args['curr_json_path'] = args['curr_bin_path'].replace('.bin', '.json') + + result = run_one_point_with_stream(g_p_net, g_i_net, args) + + result['ds_name'] = args['ds_name'] + result['seq'] = args['seq'] + result['rate_idx'] = args['rate_idx'] + return result def main(): @@ -419,9 +479,10 @@ def main(): args = parse_args() - if args.force_zero_thres is not None and args.force_zero_thres < 0: - args.force_zero_thres = None + if not torch.cuda.is_available(): + raise RuntimeError('test_video.py requires CUDA (torch.cuda.is_available() is False)') + args.skip_thres = max(0, args.skip_thres) if args.cuda_idx is not None: cuda_device = ','.join([str(s) for s in args.cuda_idx]) os.environ['CUDA_VISIBLE_DEVICES'] = cuda_device @@ -432,11 +493,8 @@ def main(): with open(args.test_config) as f: config = json.load(f) - gpu_num = 0 - if args.cuda: - gpu_num = torch.cuda.device_count() - - multiprocessing.set_start_method("spawn") + gpu_num = torch.cuda.device_count() + multiprocessing.set_start_method('spawn') threadpool_executor = concurrent.futures.ProcessPoolExecutor(max_workers=worker_num, initializer=init_func, initargs=(args, gpu_num)) @@ -451,8 +509,8 @@ def main(): assert len(args.qp_i) == rate_num qp_i = args.qp_i else: - assert 2 <= rate_num <= DMC.get_qp_num() - for i in np.linspace(0, DMC.get_qp_num() - 1, num=rate_num): + assert 2 <= rate_num <= DMCI.qp_num() + for i in np.linspace(0, DMCI.qp_num() - 1, num=rate_num): qp_i.append(int(i+0.5)) if not args.force_intra: @@ -462,10 +520,7 @@ def main(): else: qp_p = qp_i - print(f"testing {rate_num} rates, using qp: ", end='') - for q in qp_i: - print(f"{q}, ", end='') - print() + print(f'testing {rate_num} rates, using qp: {', '.join(str(q) for q in qp_i)}') root_path = args.force_root_path if args.force_root_path is not None else config['root_path'] config = config['test_classes'] @@ -496,7 +551,6 @@ def main(): cur_args['frame_num'] = args.force_frame_num cur_args['calc_ssim'] = args.calc_ssim cur_args['dataset_path'] = os.path.join(root_path, config[ds_name]['base_path']) - cur_args['write_stream'] = args.write_stream cur_args['check_existing'] = args.check_existing cur_args['stream_path'] = args.stream_path cur_args['save_decoded_frame'] = args.save_decoded_frame @@ -523,7 +577,7 @@ def main(): log_result[ds_name][seq] = {} for res in results: - log_result[res['ds_name']][res['seq']][f"{res['rate_idx']:03d}"] = res + log_result[res['ds_name']][res['seq']][f'{res['rate_idx']:03d}'] = res out_json_dir = os.path.dirname(args.output_path) if len(out_json_dir) > 0: @@ -537,5 +591,5 @@ def main(): print(f'Total elapsed time: {total_minutes:.1f} min') -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/third_party/.gitkeep b/third_party/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/train_image.py b/train_image.py new file mode 100644 index 0000000..700941d --- /dev/null +++ b/train_image.py @@ -0,0 +1,140 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import argparse +import math +import sys +import time +import torch +import torch.distributed as dist + +from torch.nn.utils import clip_grad_norm_ + +from src.datasets.image_dataset import ImageFolder +from src.models.image_model import DMCI +from src.utils.common import start_train, save_ckpt, save_status, get_current_device, \ + get_training_lambdas, get_dataloader, init_train, cleanup_train, load_existing_weights, wrap_ddp + + +def get_training_strategy(): + # epoch is for referencing purpose + # lr is the learning rate for the current epoch + training_strategy = \ + [[0, 2e-4, 256, 256]] * 45 + \ + [[49, 5e-5, 256, 256]] * 25 + \ + [[69, 1e-5, 256, 256]] * 20 + \ + [[90, 2e-4, 512, 512]] * 5 + \ + [[95, 5e-5, 512, 512]] * 4 + \ + [[99, 1e-5, 512, 512]] * 4 + \ + [[103, 1e-6, 512, 512]] * 2 + \ + [[105, 1e-6, 512, 512]] # noqa: E501 E221 + # epo, lr, patch_size # noqa: E116 E501 + + return training_strategy + + +def parse_args(argv): + parser = argparse.ArgumentParser() + + parser.add_argument('--batch_size', type=int, default=16) + parser.add_argument('-e', '--epochs', default=104, type=int) + parser.add_argument('--lambdas', type=float, nargs='+', required=True) + parser.add_argument('-n', '--num_workers', type=int, default=4, + help='Dataloaders worker per trainer') + parser.add_argument('--save_dir', type=str, required=True, help='Path to save models') + parser.add_argument('--train_dataset', type=str, required=True) + + args = parser.parse_args(argv) + return args + + +def train_one_epoch(i_net, dataloader, optimizer, epoch, rank): + training_strategy = get_training_strategy() + i_net.train() + device = next(i_net.parameters()).device + + idx = min(len(training_strategy) - 1, epoch) + _, lr, patch_width, patch_height = training_strategy[idx] + + for g in optimizer.param_groups: + g['lr'] = lr + + world_size = dist.get_world_size() if rank >= 0 else 1 + dataloader.dataset.set_patch_size(patch_width, patch_height) + + t0 = time.time() + for i, batch in enumerate(dataloader): + batch = [t.to(device) for t in batch] + batch_size = batch[0].size(0) + qp = batch[-2] + curr_lambdas = batch[-1] + + print_loss_info = rank <= 0 and i % 200 == 0 + + loss, info = i_net(batch[0], qp, lambdas=curr_lambdas, get_loss_info=print_loss_info) + optimizer.zero_grad() + loss.backward() + + total_norm = clip_grad_norm_(i_net.parameters(), max_norm=0.1, + error_if_nonfinite=False).item() + if math.isnan(total_norm) or math.isinf(total_norm): + if rank <= 0: + print('non-finite norm, skip this batch') + continue + + optimizer.step() + + if print_loss_info: + numer = i * batch_size * world_size + denom = len(dataloader.dataset) + t1 = time.time() + print( + f'Time: {t1-t0:.3f} seconds, Train epoch {epoch}:' + f' [{numer} / {denom} ({100. * numer / denom:.0f}%)]' + f' MSE: {info['mse']} | Bpp y: {info['bpp_y']} | Bpp z: {info['bpp_z']} |' + f' Losses: {info['losses']} | lr: {optimizer.param_groups[0]['lr']:.1e}' + ) + t0 = t1 + + +def train(rank, args): + world_size = init_train(rank, args.save_dir) + train_dataset = ImageFolder(args.train_dataset, 256, 256, DMCI.qp_num(), + get_training_lambdas(args.lambdas, DMCI.qp_num())) + + i_net = DMCI() + begin_epoch, opt_status = load_existing_weights(args.save_dir, i_net, rank) + + device = get_current_device(rank) + if rank >= 0: + i_net = i_net.cuda(rank) + else: + i_net = i_net.to(device) + i_net = wrap_ddp(i_net, rank) + + optimizer = torch.optim.AdamW(i_net.parameters(), lr=1e-4) + if opt_status is not None: + optimizer.load_state_dict(opt_status) + + dataloader = get_dataloader(train_dataset, rank, world_size, args.batch_size, + args.num_workers) + for epoch in range(begin_epoch, args.epochs): + if rank >= 0: + dataloader.sampler.set_epoch(epoch) + train_one_epoch(i_net, dataloader, optimizer, epoch, rank) + + if rank <= 0: + save_status(args.save_dir, i_net, optimizer, epoch) + + if rank <= 0: + save_ckpt(args.save_dir, i_net) + cleanup_train(rank) + + +def main(argv): + args = parse_args(argv) + start_train(train, args) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/train_video.py b/train_video.py new file mode 100644 index 0000000..99ec658 --- /dev/null +++ b/train_video.py @@ -0,0 +1,249 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import argparse +import math +import sys +import time +import torch +import torch.distributed as dist + +from torch.nn.parallel import DistributedDataParallel as DDP +from torch.nn.utils import clip_grad_norm_ + +from src.datasets.video_dataset import VideoFolder +from src.models.image_model import DMCI +from src.utils.common import ModelStructure, save_status, start_train, save_ckpt, \ + get_current_device, get_training_lambdas, get_dataloader, init_train, cleanup_train, \ + load_existing_weights, get_state_dict, wrap_ddp + + +def get_training_strategy(training_scheduling, frame_delay, model_structure): + # epoch is for referencing purpose + # lr is the learning rate for the current epoch + if model_structure == ModelStructure.LD: + if training_scheduling == 'stage0': + training_strategy = \ + [[0, 1e-4, 2, False, 256, 256]] * 5 + \ + [[5, 1e-4, 3, False, 256, 256]] * 5 + \ + [[10, 1e-4, 6, False, 256, 256]] * 45 + \ + [[55, 1e-4, 6, False, 256, 256]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + elif training_scheduling == 'stage1': + training_strategy = \ + [[0, 5e-5, 8, True, 256, 256]] * 5 + \ + [[5, 5e-5, 16, True, 256, 256]] * 5 + \ + [[10, 5e-5, 24, True, 256, 256]] * 5 + \ + [[15, 5e-5, 32, True, 256, 256]] * 15 + \ + [[30, 5e-6, 32, True, 256, 256]] * 7 + \ + [[37, 5e-6, 32, True, 256, 256]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + elif training_scheduling == 'stage2': + training_strategy = \ + [[0, 5e-5, 33, True, 512, 512]] * 14 + \ + [[14, 5e-6, 33, True, 512, 512]] * 4 + \ + [[18, 2e-5, 49, True, 512, 512]] * 7 + \ + [[25, 2e-6, 49, True, 512, 512]] * 2 + \ + [[27, 5e-6, 65, True, 512, 512]] * 7 + \ + [[34, 2e-6, 65, True, 512, 512]] * 6 + \ + [[40, 2e-6, 65, True, 512, 512]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + elif training_scheduling == 'stage3': + training_strategy = \ + [[0, 2e-6, 97, True, 512, 512]] * 2 + \ + [[2, 5e-7, 129, True, 512, 512]] * 2 + \ + [[4, 5e-7, 129, True, 512, 512]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + else: + assert False + + return training_strategy + + if training_scheduling == 'stage0': + training_strategy = \ + [[0, 1e-4, 1 + 1 * frame_delay, False, 256, 256]] * 5 + \ + [[5, 1e-4, 1 + 2 * frame_delay, False, 256, 256]] * 5 + \ + [[10, 1e-4, 1 + 4 * frame_delay, False, 256, 256]] * 35 + \ + [[45, 1e-4, 1 + 4 * frame_delay, False, 256, 256]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + elif training_scheduling == 'stage1': + training_strategy = \ + [[0, 5e-5, 17, True, 256, 256]] * 2 + \ + [[2, 5e-5, 25, True, 256, 256]] * 1 + \ + [[3, 5e-5, 33, True, 256, 256]] * 3 + \ + [[6, 5e-6, 33, True, 256, 256]] * 4 + \ + [[10, 5e-6, 33, True, 256, 256]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + elif training_scheduling == 'stage2': + training_strategy = \ + [[0, 5e-5, 33, True, 512, 512]] * 10 + \ + [[10, 5e-5, 49, True, 512, 512]] * 10 + \ + [[20, 1e-5, 65, True, 512, 512]] * 12 + \ + [[32, 2e-6, 65, True, 512, 512]] * 8 + \ + [[40, 2e-6, 65, True, 512, 512]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + elif training_scheduling == 'stage3': + training_strategy = \ + [[0, 1e-5, 97, True, 512, 512]] * 2 + \ + [[2, 2e-6, 129, True, 512, 512]] * 2 + \ + [[4, 2e-6, 129, True, 512, 512]] # noqa: E501 E221 + # epo, lr, frame_num, cascade, patch_size # noqa: E116 E501 + else: + assert False + + return training_strategy + + +def parse_args(argv): + parser = argparse.ArgumentParser() + + parser.add_argument('--batch_size', type=int, default=16) + parser.add_argument('-e', '--epochs', default=100, type=int) + parser.add_argument('--lambdas', type=float, nargs='+', required=True) + parser.add_argument('--model_path_i', type=str, required=True) + parser.add_argument('--model_structure', type=str, default='ld', choices=['htl', 'hts', 'ld']) + parser.add_argument('-n', '--num_workers', type=int, default=4, + help='Dataloaders worker per trainer') + parser.add_argument('--save_dir', type=str, required=True, help='Path to save models') + parser.add_argument('--train_dataset', type=str, required=True) + parser.add_argument('--pretrain_path', type=str, default=None) + parser.add_argument('--training_scheduling', type=str, default='stage0', + choices=['stage0', 'stage1', 'stage2', 'stage3'], + help='How to schedule the training strategy') + + args = parser.parse_args(argv) + return args + + +def train_one_epoch(p_net, i_net, args, dataloader, optimizer, epoch, rank, + frame_delay, model_structure): + p_net_module = p_net.module if isinstance(p_net, DDP) else p_net + training_strategy = get_training_strategy(args.training_scheduling, frame_delay, + model_structure) + p_net.train() + device = next(p_net.parameters()).device + + idx = min(len(training_strategy) - 1, epoch) + _, lr, train_seq_length, is_cascaded, patch_width, patch_height = training_strategy[idx] + + for g in optimizer.param_groups: + g['lr'] = lr + + world_size = dist.get_world_size() if rank >= 0 else 1 + use_ckpt = is_cascaded and patch_width > 256 + p_net_module.set_use_ckpt(use_ckpt) + + dataloader.dataset.set_frame_num(train_seq_length) + dataloader.dataset.set_patch_size(patch_width, patch_height) + + t0 = time.time() + for i, batch in enumerate(dataloader): + batch = [t.to(device) for t in batch] + batch_size = batch[0].size(0) + frame_nums = len(batch) - 2 + frame_stop = 2 if is_cascaded else frame_nums + qp = batch[-2] + curr_lambdas = batch[-1] + + print_loss_info = rank <= 0 and i % (100 if train_seq_length >= 8 else 200) == 0 + + ref_frame = batch[0] + if train_seq_length > 1 + 1 * frame_delay or is_cascaded: + with torch.inference_mode(): + ref_frame = i_net.forward_one_frame(ref_frame, qp, recon_only=True) + + p_net_module.clear_dpb() + p_net_module.add_ref_feature_from_frame(ref_frame, apply_feature_adaptor=False) + + for frame_idx in range(1, frame_stop): + if is_cascaded: + cur_frame = batch[1:-2] + else: + cur_frame = batch[frame_idx] + loss, info = p_net(cur_frame, qp, lambdas=curr_lambdas, get_loss_info=print_loss_info, + curr_poc=frame_idx) + + optimizer.zero_grad() + loss.backward() + + total_norm = clip_grad_norm_(p_net.parameters(), max_norm=0.2, + error_if_nonfinite=False).item() + if math.isnan(total_norm) or math.isinf(total_norm): + if rank <= 0: + print('non-finite norm, skip this batch') + continue + + optimizer.step() + + if print_loss_info: + numer = i * batch_size * world_size + denom = len(dataloader.dataset) + t1 = time.time() + print( + f'Time: {t1-t0:.3f} seconds, Train epoch {epoch}:' + f' [{numer} / {denom} ({100. * numer / denom:.0f}%)]' + f' MSE: {info['mse']} | Bpp y: {info['bpp_y']} | Bpp z: {info['bpp_z']} |' + f' Losses: {info['losses']} | lr: {optimizer.param_groups[0]['lr']:.1e}' + ) + t0 = t1 + + +def train(rank, args): + world_size = init_train(rank, args.save_dir) + model_structure = ModelStructure(args.model_structure) + if model_structure == ModelStructure.LD: + from src.models.video_model_ld import DMC, g_frame_delay as frame_delay + else: + from src.models.video_model_ht import DMC, g_frame_delay as frame_delay + train_dataset = VideoFolder(args.train_dataset, 256, 256, DMCI.qp_num(), + get_training_lambdas(args.lambdas, DMCI.qp_num()), + group_of_pictures=frame_delay) + + i_state_dict = get_state_dict(args.model_path_i) + i_net = DMCI() + i_net.load_state_dict(i_state_dict) + i_net = i_net.eval() + + if model_structure == ModelStructure.LD: + p_net = DMC() + else: + p_net = DMC(model_structure=model_structure) + begin_epoch, opt_status = load_existing_weights( + args.save_dir, p_net, rank, args.pretrain_path) + + device = get_current_device(rank) + if rank >= 0: + p_net = p_net.cuda(rank) + i_net = i_net.cuda(rank) + else: + p_net = p_net.to(device) + i_net = i_net.to(device) + p_net = wrap_ddp(p_net, rank, find_unused_parameters=True) + + optimizer = torch.optim.AdamW(p_net.parameters(), lr=1e-4) + if opt_status is not None: + optimizer.load_state_dict(opt_status) + + dataloader = get_dataloader(train_dataset, rank, world_size, args.batch_size, + args.num_workers) + for epoch in range(begin_epoch, args.epochs): + if rank >= 0: + dataloader.sampler.set_epoch(epoch) + train_one_epoch(p_net, i_net, args, dataloader, optimizer, epoch, rank, + frame_delay, model_structure) + + if rank <= 0: + save_status(args.save_dir, p_net, optimizer, epoch) + + if rank <= 0: + save_ckpt(args.save_dir, p_net) + cleanup_train(rank) + + +def main(argv): + args = parse_args(argv) + start_train(train, args) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/training.md b/training.md new file mode 100644 index 0000000..09cf956 --- /dev/null +++ b/training.md @@ -0,0 +1,378 @@ +# Training DCVC-UF + +This document describes how to train DCVC-UF and DCVC-UF-Intra from scratch, including the dataset format, launcher scripts, and the multi-stage training schedule. + +## Train dataset + +Training uses RGB PNG images. The dataset loaders are implemented in `src/datasets/image_dataset.py` (`ImageFolder`) and `src/datasets/video_dataset.py` (`VideoFolder`). + +### Image dataset + +Organize a collection of PNG images under a root folder and provide a `description.json` that lists the relative path of each image: + +``` +/path/to/image_dataset/ +├── description.json +├── img_000001.png +├── img_000002.png +└── ... +``` + +`description.json` is a flat JSON array of relative image paths: +```json +[ + "img_000001.png", + "img_000002.png", + "..." +] +``` + +### Video dataset + +Organize video sequences as folders of numbered PNG frames under a root folder and provide a `description.json` that describes the sequences: + +``` +/path/to/video_dataset/ +├── description.json +├── sequence_001/ +│ ├── im00001.png +│ ├── im00002.png +│ └── ... +├── sequence_002/ +│ ├── im00001.png +│ └── ... +└── ... +``` + +`description.json` contains two fields — `seqs` (a list of sequence metadata) and `frames` (a list of frame filenames): +```json +{ + "seqs": [ + { + "path": "sequence_001", + "width": 1920, + "height": 1080, + "seq_length": 100 + }, + { + "path": "sequence_002", + "width": 1280, + "height": 720, + "seq_length": 200 + } + ], + "frames": [ + "im00001.png", + "im00002.png", + "im00003.png", + "..." + ] +} +``` + +The `frames` list is shared across all sequences (i.e., all sequences use the same frame naming scheme). Each entry in `seqs` specifies the subdirectory path, resolution, and number of frames for that sequence. + +## Train the image model (DCVC-UF-Intra) + +Create a `train_image.sh` file with the contents below, edit the user-configurable variables, then run: + +```bash +bash train_image.sh +``` + +The script trains for 105 epochs with an adaptive learning rate schedule (1e-6 to 2e-4) and progressive patch sizes (256x256 → 512x512). + +**Training dataset:** We used subsets 0, 1, and 2 of the [Open Images](https://github.com/cvdfoundation/open-images-dataset) training set. + +### `train_image.sh` + +```bash +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Train the DMCI image model from scratch. +# 1 stage: 105 epochs, 256x256 patches for first 90 epochs, then 512x512. + +set -e + +# ========== User-configurable variables ========== +TRAIN_DATASET=/path/to/image_dataset +SAVE_DIR=/path/to/output/image_model +LAMBDAS="10 2048" +# ================================================== + +python train_image.py \ + --train_dataset ${TRAIN_DATASET} \ + --save_dir ${SAVE_DIR} \ + --lambdas ${LAMBDAS} \ + --batch_size 16 \ + -n 4 \ + -e 105 +``` + +## Train the video model (DCVC-UF) + +Each variant uses its own launcher script. Create the launcher file shown below for the variant(s) you want to train, edit the user-configurable variables (dataset paths, pretrained image model path, save directory), then run: + +```bash +bash train_video_htl.sh # HT-L variant +bash train_video_hts.sh # HT-S variant +bash train_video_ld.sh # LD variant +``` + +Training requires a pretrained image model (DCVC-UF-Intra). Each script runs a multi-stage pipeline that progressively increases the sequence length and patch size. Longer training sequences enable the model to learn more comprehensive temporal dependencies through cross-chunk feature propagation, which is a key advantage of the chunk-based framework. + +- **HT-L/HT-S**: 4 stages, 99 epochs total, with cascading loss from stage 1 +- **LD**: 4 stages, 136 epochs total, with cascading loss from stage 1 + +**Training datasets:** We used two video datasets for training: +1. The septuplet subset of [Vimeo-90k](http://toflow.csail.mit.edu/index.html). +2. We also process the [original videos](http://data.csail.mit.edu/tofu/dataset/original_video_list.txt) of [Vimeo-90k](http://toflow.csail.mit.edu/index.html) to generate long sequences. + +### `train_video_htl.sh` + +```bash +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Train the DMC-HTL video model (high throughput, frame_delay=8). +# 4 stages: +# stage0: 45 epochs, non-cascaded, 256x256 +# stage1: 10 epochs, cascaded, 256x256 +# stage2: 40 epochs, cascaded, 512x512 +# stage3: 4 epochs, cascaded, 512x512 + +set -e + +# ========== User-configurable variables ========== +TRAIN_DATASET_STAGE0=/path/to/video_dataset_stage0 +TRAIN_DATASET_STAGE1=/path/to/video_dataset_stage1 +TRAIN_DATASET_STAGE2=/path/to/video_dataset_stage2 +TRAIN_DATASET_STAGE3=/path/to/video_dataset_stage3 + +MODEL_PATH_I=/path/to/image_model.pth.tar +SAVE_DIR=/path/to/output/video_model_htl +LAMBDAS="1 768" +# ================================================== + +MODEL_STRUCTURE=htl + +# stage0: base training +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE0} \ + --save_dir ${SAVE_DIR}/s0 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage0 \ + --batch_size 16 \ + -n 4 \ + -e 45 + +# stage1: cascaded finetuning at 256x256 +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE1} \ + --save_dir ${SAVE_DIR}/s1 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage1 \ + --pretrain_path ${SAVE_DIR}/s0/ckpt.pth.tar \ + --batch_size 8 \ + -n 4 \ + -e 10 + +# stage2: cascaded finetuning at 512x512 +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE2} \ + --save_dir ${SAVE_DIR}/s2 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage2 \ + --pretrain_path ${SAVE_DIR}/s1/ckpt.pth.tar \ + --batch_size 8 \ + -n 8 \ + -e 40 + +# stage3: cascaded finetuning at 512x512 with longer sequences +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE3} \ + --save_dir ${SAVE_DIR}/s3 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage3 \ + --pretrain_path ${SAVE_DIR}/s2/ckpt.pth.tar \ + --batch_size 16 \ + -n 8 \ + -e 4 +``` + +### `train_video_hts.sh` + +```bash +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Train the DMC-HTS video model (high throughput, frame_delay=8). +# 4 stages: +# stage0: 45 epochs, non-cascaded, 256x256 +# stage1: 10 epochs, cascaded, 256x256 +# stage2: 40 epochs, cascaded, 512x512 +# stage3: 4 epochs, cascaded, 512x512 + +set -e + +# ========== User-configurable variables ========== +TRAIN_DATASET_STAGE0=/path/to/video_dataset_stage0 +TRAIN_DATASET_STAGE1=/path/to/video_dataset_stage1 +TRAIN_DATASET_STAGE2=/path/to/video_dataset_stage2 +TRAIN_DATASET_STAGE3=/path/to/video_dataset_stage3 + +MODEL_PATH_I=/path/to/image_model.pth.tar +SAVE_DIR=/path/to/output/video_model_hts +LAMBDAS="1 768" +# ================================================== + +MODEL_STRUCTURE=hts + +# stage0: base training +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE0} \ + --save_dir ${SAVE_DIR}/s0 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage0 \ + --batch_size 16 \ + -n 4 \ + -e 45 + +# stage1: cascaded finetuning at 256x256 +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE1} \ + --save_dir ${SAVE_DIR}/s1 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage1 \ + --pretrain_path ${SAVE_DIR}/s0/ckpt.pth.tar \ + --batch_size 8 \ + -n 4 \ + -e 10 + +# stage2: cascaded finetuning at 512x512 +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE2} \ + --save_dir ${SAVE_DIR}/s2 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage2 \ + --pretrain_path ${SAVE_DIR}/s1/ckpt.pth.tar \ + --batch_size 8 \ + -n 8 \ + -e 40 + +# stage3: cascaded finetuning at 512x512 with longer sequences +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE3} \ + --save_dir ${SAVE_DIR}/s3 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage3 \ + --pretrain_path ${SAVE_DIR}/s2/ckpt.pth.tar \ + --batch_size 16 \ + -n 8 \ + -e 4 +``` + +### `train_video_ld.sh` + +```bash +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Train the DMC-LD video model (low delay, frame_delay=1). +# 4 stages: +# stage0: 55 epochs, non-cascaded, 256x256 +# stage1: 37 epochs, cascaded, 256x256 +# stage2: 40 epochs, cascaded, 512x512 +# stage3: 4 epochs, cascaded, 512x512 + +set -e + +# ========== User-configurable variables ========== +TRAIN_DATASET_STAGE0=/path/to/video_dataset_stage0 +TRAIN_DATASET_STAGE1=/path/to/video_dataset_stage1 +TRAIN_DATASET_STAGE2=/path/to/video_dataset_stage2 +TRAIN_DATASET_STAGE3=/path/to/video_dataset_stage3 + +MODEL_PATH_I=/path/to/image_model.pth.tar +SAVE_DIR=/path/to/output/video_model_ld +LAMBDAS="1 768" +# ================================================== + +MODEL_STRUCTURE=ld + +# stage0: base training +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE0} \ + --save_dir ${SAVE_DIR}/s0 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage0 \ + --batch_size 16 \ + -n 4 \ + -e 55 + +# stage1: cascaded finetuning at 256x256 +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE1} \ + --save_dir ${SAVE_DIR}/s1 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage1 \ + --pretrain_path ${SAVE_DIR}/s0/ckpt.pth.tar \ + --batch_size 8 \ + -n 4 \ + -e 37 + +# stage2: cascaded finetuning at 512x512 +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE2} \ + --save_dir ${SAVE_DIR}/s2 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage2 \ + --pretrain_path ${SAVE_DIR}/s1/ckpt.pth.tar \ + --batch_size 8 \ + -n 8 \ + -e 40 + +# stage3: cascaded finetuning at 512x512 with longer sequences +python train_video.py \ + --model_structure ${MODEL_STRUCTURE} \ + --model_path_i ${MODEL_PATH_I} \ + --train_dataset ${TRAIN_DATASET_STAGE3} \ + --save_dir ${SAVE_DIR}/s3 \ + --lambdas ${LAMBDAS} \ + --training_scheduling stage3 \ + --pretrain_path ${SAVE_DIR}/s2/ckpt.pth.tar \ + --batch_size 4 \ + -n 8 \ + -e 4 +```
    DCVC - Paper (NeurIPS 2021) & + + Paper (NeurIPS 2021) & Paper (arXiv) CodeCode Checkpoints
    DCVC-TCM - Paper (IEEE TMM) & + Paper (IEEE TMM) & Paper (arXiv) Code
    DCVC-HEM - Paper (ACM MM 2022) & + Paper (ACM MM 2022) & Paper (arXiv) Code
    DCVC-DC - Paper (CVPR 2023) & + Paper (CVPR 2023) & Paper (arXiv) Code
    DCVC-FM - Paper (CVPR 2024) & + Paper (CVPR 2024) & Paper (arXiv) Code
    DCVC-RT - Paper (CVPR 2025) & + Paper (CVPR 2025) & Paper (arXiv) CodeCode Checkpoints
    DCVC-UF + Paper (CVPR 2026) & + Paper (arXiv) + CodeCheckpoints
    EVC - Paper (ICLR 2023) & + Paper (ICLR 2023) & Paper (arXiv) Code