Commit fd18d5df authored by Deb Mukherjee's avatar Deb Mukherjee

Modeling default coef probs with distribution

Replaces the default tables for single coefficient magnitudes with
those obtained from an appropriate distribution. The EOB node
is left unchanged. The model is represeted as a 256-size codebook
where the index corresponds to the probability of the Zero or the
One node. Two variations are implemented corresponding to whether
the Zero node or the One-node is used as the peg. The main advantage
is that the default prob tables will become considerably smaller and
manageable. Besides there is substantially less risk of over-fitting
for a training set.

Various distributions are tried and the one that gives the best
results is the family of Generalized Gaussian distributions with
shape parameter 0.75. The results are within about 0.2% of fully
trained tables for the Zero peg variant, and within 0.1% of the
One peg variant.

The forward updates are optionally (controlled by a macro)
model-based, i.e. restricted to only convey probabilities from the
codebook. Backward updates can also be optionally (controlled by
another macro) model-based, but is turned off by default. Currently
model-based forward updates work about the same as unconstrained
updates, but there is a drop in performance with backward-updates
being model based.

The model based approach also allows the probabilities for the key
frames to be adjusted from the defaults based on the base_qindex of
the frame. Currently the adjustment function is a placeholder that
adjusts the prob of EOB and Zero node from the nominal one at higher
quality (lower qindex) or lower quality (higher qindex) ends of the
range. The rest of the probabilities are then derived based on the
model from the adjusted prob of zero.

Change-Id: Iae050f3cbcc6d8b3f204e8dc395ae47b3b2192c9
parent 66eff0aa
......@@ -247,6 +247,7 @@ EXPERIMENT_LIST="
abovesprefmv
code_nonzerocount
useselectrefmv
modelcoefprob
"
CONFIG_LIST="
external_build
......
......@@ -13,9 +13,10 @@
/* Update probabilities for the nodes in the token entropy tree.
Generated file included by vp9_entropy.c */
#define COEF_UPDATE_PROB 252
#define COEF_UPDATE_PROB_8X8 252
#define COEF_UPDATE_PROB_16X16 252
static const vp9_prob vp9_coef_update_prob[ENTROPY_NODES] = {
252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252
};
#if CONFIG_CODE_NONZEROCOUNT
#define NZC_UPDATE_PROB_4X4 252
......@@ -25,4 +26,8 @@
#define NZC_UPDATE_PROB_PCAT 252
#endif
#if CONFIG_MODELCOEFPROB
#define COEF_MODEL_UPDATE_PROB 16
#endif
#endif // VP9_COMMON_VP9_COEFUPDATEPROBS_H__
......@@ -11,6 +11,10 @@
/*Generated file, included by vp9_entropy.c*/
// NOTE: When the CONFIG_MODELCOEFPROB experiment is on, only the first
// 2 or 3 from each row is actually used depending on whether
// UNCONSTRAINDED_NODES is 2 or 3. If this experiment is merged
// the tables below should be shortened accordingly.
static const vp9_coeff_probs default_coef_probs_4x4[BLOCK_TYPES] = {
{ /* block Type 0 */
{ /* Intra */
......
This diff is collapsed.
......@@ -15,7 +15,6 @@
#include "vp9/common/vp9_treecoder.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_coefupdateprobs.h"
extern const int vp9_i8x8_block[4];
......@@ -142,6 +141,33 @@ static int get_coef_band(TX_SIZE tx_size, int coef_index) {
}
extern int vp9_get_coef_context(int * recent_energy, int token);
#if CONFIG_MODELCOEFPROB
#define COEFPROB_BITS 8
#define COEFPROB_MODELS (1 << COEFPROB_BITS)
// 2 => EOB and Zero nodes are unconstrained, rest are modeled
// 3 => EOB, Zero and One nodes are unconstrained, rest are modeled
#define UNCONSTRAINED_NODES 3 // Choose one of 2 or 3
// whether forward updates are model-based
#define MODEL_BASED_UPDATE 0
// if model-based how many nodes are unconstrained
#define UNCONSTRAINED_UPDATE_NODES 3
// whether backward updates are model-based
#define MODEL_BASED_ADAPT 0
#define UNCONSTRAINED_ADAPT_NODES 3
// whether to adjust the coef probs for key frames based on qindex
#define ADJUST_KF_COEF_PROBS 0
typedef vp9_prob vp9_coeff_probs_model[REF_TYPES][COEF_BANDS]
[PREV_COEF_CONTEXTS][2];
extern const vp9_prob vp9_modelcoefprobs[COEFPROB_MODELS][ENTROPY_NODES - 1];
void vp9_get_model_distribution(vp9_prob model, vp9_prob *tree_probs,
int b, int r);
void vp9_adjust_default_coef_probs(struct VP9Common *cm);
#endif // CONFIG_MODELCOEFPROB
#if CONFIG_CODE_NONZEROCOUNT
/* Alphabet for number of non-zero symbols in block */
#define NZC_0 0 /* Used for all blocks */
......@@ -224,4 +250,7 @@ extern const int vp9_extranzcbits[NZC32X32_TOKENS];
extern const int vp9_basenzcvalue[NZC32X32_TOKENS];
#endif // CONFIG_CODE_NONZEROCOUNT
#include "vp9/common/vp9_coefupdateprobs.h"
#endif // VP9_COMMON_VP9_ENTROPY_H_
......@@ -1197,6 +1197,12 @@ static void read_nzc_probs(VP9_COMMON *cm,
static void read_coef_probs_common(BOOL_DECODER* const bc,
vp9_coeff_probs *coef_probs,
int block_types) {
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
const int entropy_nodes_update = UNCONSTRAINED_UPDATE_NODES;
#else
const int entropy_nodes_update = ENTROPY_NODES;
#endif
int i, j, k, l, m;
if (vp9_read_bit(bc)) {
......@@ -1206,11 +1212,15 @@ static void read_coef_probs_common(BOOL_DECODER* const bc,
for (l = 0; l < PREV_COEF_CONTEXTS; l++) {
if (l >= 3 && k == 0)
continue;
for (m = CONFIG_CODE_NONZEROCOUNT; m < ENTROPY_NODES; m++) {
for (m = CONFIG_CODE_NONZEROCOUNT; m < entropy_nodes_update; m++) {
vp9_prob *const p = coef_probs[i][j][k][l] + m;
if (vp9_read(bc, COEF_UPDATE_PROB)) {
if (vp9_read(bc, vp9_coef_update_prob[m])) {
*p = read_prob_diff_update(bc, *p);
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
if (m == 1)
vp9_get_model_distribution(*p, coef_probs[i][j][k][l], i, j);
#endif
}
}
}
......@@ -1611,6 +1621,10 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) {
}
}
}
#if CONFIG_MODELCOEFPROB && ADJUST_KF_COEF_PROBS
if (pc->frame_type == KEY_FRAME)
vp9_adjust_default_coef_probs(pc);
#endif
#if CONFIG_NEW_MVREF
// If Key frame reset mv ref id probabilities to defaults
......
......@@ -399,6 +399,43 @@ static int prob_diff_update_savings_search(const unsigned int *ct,
return bestsavings;
}
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
static int prob_diff_update_savings_search_model(const unsigned int *ct,
const vp9_prob *oldp,
vp9_prob *bestp,
const vp9_prob upd,
int b, int r) {
int i, old_b, new_b, update_b, savings, bestsavings, step;
int newp;
vp9_prob bestnewp, newplist[ENTROPY_NODES];
for (i = UNCONSTRAINED_NODES - 1, old_b = 0; i < ENTROPY_NODES; ++i)
old_b += cost_branch256(ct + 2 * i, oldp[i]);
bestsavings = 0;
bestnewp = oldp[UNCONSTRAINED_NODES - 1];
step = (*bestp > oldp[UNCONSTRAINED_NODES - 1] ? -1 : 1);
newp = *bestp;
// newp = *bestp - step * (abs(*bestp - oldp[UNCONSTRAINED_NODES - 1]) >> 1);
for (; newp != oldp[UNCONSTRAINED_NODES - 1]; newp += step) {
if (newp < 1 || newp > 255) continue;
newplist[UNCONSTRAINED_NODES - 1] = newp;
vp9_get_model_distribution(newp, newplist, b, r);
for (i = UNCONSTRAINED_NODES - 1, new_b = 0; i < ENTROPY_NODES; ++i)
new_b += cost_branch256(ct + 2 * i, newplist[i]);
update_b = prob_diff_update_cost(newp, oldp[UNCONSTRAINED_NODES - 1]) +
vp9_cost_upd256;
savings = old_b - new_b - update_b;
if (savings > bestsavings) {
bestsavings = savings;
bestnewp = newp;
}
}
*bestp = bestnewp;
return bestsavings;
}
#endif
static void vp9_cond_prob_update(vp9_writer *bc, vp9_prob *oldp, vp9_prob upd,
unsigned int *ct) {
vp9_prob newp;
......@@ -2014,6 +2051,11 @@ static void update_coef_probs_common(vp9_writer* const bc,
int i, j, k, l, t;
int update[2] = {0, 0};
int savings;
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
const int entropy_nodes_update = UNCONSTRAINED_UPDATE_NODES;
#else
const int entropy_nodes_update = ENTROPY_NODES;
#endif
// vp9_prob bestupd = find_coef_update_prob(cpi);
/* dry run to see if there is any udpate at all needed */
......@@ -2021,20 +2063,27 @@ static void update_coef_probs_common(vp9_writer* const bc,
for (i = 0; i < block_types; ++i) {
for (j = 0; j < REF_TYPES; ++j) {
for (k = 0; k < COEF_BANDS; ++k) {
int prev_coef_savings[ENTROPY_NODES] = {0};
// int prev_coef_savings[ENTROPY_NODES] = {0};
for (l = 0; l < PREV_COEF_CONTEXTS; ++l) {
for (t = CONFIG_CODE_NONZEROCOUNT; t < ENTROPY_NODES; ++t) {
for (t = CONFIG_CODE_NONZEROCOUNT; t < entropy_nodes_update; ++t) {
vp9_prob newp = new_frame_coef_probs[i][j][k][l][t];
const vp9_prob oldp = old_frame_coef_probs[i][j][k][l][t];
const vp9_prob upd = COEF_UPDATE_PROB;
int s = prev_coef_savings[t];
const vp9_prob upd = vp9_coef_update_prob[t];
int s; // = prev_coef_savings[t];
int u = 0;
if (l >= 3 && k == 0)
continue;
#if defined(SEARCH_NEWP)
s = prob_diff_update_savings_search(frame_branch_ct[i][j][k][l][t],
oldp, &newp, upd);
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
if (t == UNCONSTRAINED_NODES - 1)
s = prob_diff_update_savings_search_model(
frame_branch_ct[i][j][k][l][0],
old_frame_coef_probs[i][j][k][l], &newp, upd, i, j);
else
#endif
s = prob_diff_update_savings_search(
frame_branch_ct[i][j][k][l][t], oldp, &newp, upd);
if (s > 0 && newp != oldp)
u = 1;
if (u)
......@@ -2061,24 +2110,32 @@ static void update_coef_probs_common(vp9_writer* const bc,
/* Is coef updated at all */
if (update[1] == 0 || savings < 0) {
vp9_write_bit(bc, 0);
} else {
return;
}
vp9_write_bit(bc, 1);
for (i = 0; i < block_types; ++i) {
for (j = 0; j < REF_TYPES; ++j) {
for (k = 0; k < COEF_BANDS; ++k) {
int prev_coef_savings[ENTROPY_NODES] = {0};
// int prev_coef_savings[ENTROPY_NODES] = {0};
for (l = 0; l < PREV_COEF_CONTEXTS; ++l) {
// calc probs and branch cts for this frame only
for (t = CONFIG_CODE_NONZEROCOUNT; t < ENTROPY_NODES; ++t) {
for (t = CONFIG_CODE_NONZEROCOUNT; t < entropy_nodes_update; ++t) {
vp9_prob newp = new_frame_coef_probs[i][j][k][l][t];
vp9_prob *oldp = old_frame_coef_probs[i][j][k][l] + t;
const vp9_prob upd = COEF_UPDATE_PROB;
int s = prev_coef_savings[t];
const vp9_prob upd = vp9_coef_update_prob[t];
int s; // = prev_coef_savings[t];
int u = 0;
if (l >= 3 && k == 0)
continue;
#if defined(SEARCH_NEWP)
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
if (t == UNCONSTRAINED_NODES - 1)
s = prob_diff_update_savings_search_model(
frame_branch_ct[i][j][k][l][0],
old_frame_coef_probs[i][j][k][l], &newp, upd, i, j);
else
#endif
s = prob_diff_update_savings_search(
frame_branch_ct[i][j][k][l][t],
*oldp, &newp, upd);
......@@ -2099,7 +2156,11 @@ static void update_coef_probs_common(vp9_writer* const bc,
/* send/use new probability */
write_prob_diff_update(bc, newp, *oldp);
*oldp = newp;
}
#if CONFIG_MODELCOEFPROB && MODEL_BASED_UPDATE
if (t == UNCONSTRAINED_NODES - 1)
vp9_get_model_distribution(
newp, old_frame_coef_probs[i][j][k][l], i, j);
#endif
}
}
}
......
......@@ -1287,9 +1287,6 @@ static void encode_frame_internal(VP9_COMP *cpi) {
vp9_zero(cpi->mb_mv_ref_count);
#endif
// force lossless mode
if (cm->base_qindex <= 4)
cm->base_qindex = 0;
cpi->mb.e_mbd.lossless = (cm->base_qindex == 0 &&
cm->y1dc_delta_q == 0 &&
cm->uvdc_delta_q == 0 &&
......
......@@ -3052,6 +3052,10 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
}
// transform / motion compensation build reconstruction frame
#if CONFIG_MODELCOEFPROB && ADJUST_KF_COEF_PROBS
if (cm->frame_type == KEY_FRAME)
vp9_adjust_default_coef_probs(cm);
#endif
vp9_encode_frame(cpi);
......
......@@ -730,6 +730,10 @@ void vp9_set_quantizer(struct VP9_COMP *cpi, int Q) {
cm->base_qindex = Q;
// Set lossless mode
if (cm->base_qindex <= 4)
cm->base_qindex = 0;
// if any of the delta_q values are changing update flag will
// have to be set.
cm->y1dc_delta_q = 0;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment