Методы контекстного моделирования
Пример работы алгоритма PPM
Рассмотрим подробнее работу алгоритма PPM с помощью примера.
Пример 2
Имеется последовательность символов "абвавабввбббв" алфавита {'а', 'б', 'в', 'г'}, которая уже была закодирована. (см. рис. 3.3)
Пусть счетчик символа ухода равен 1 для всех КМ, при обновлении модели счетчики символов увеличиваются на 1 во всех активных КМ, применяется метод исключения, и максимальная длина контекста равна 3, т.е. N = 3.
Первоначально модель состоит из КМ(-1), в которой счетчики всех четырех символов алфавита имеют значение 1. Состояние модели обработки последовательности "абвавабввбббв" представлено на рис. 3.4, где прямоугольниками обозначены контекстные модели, при этом для каждой КМ указан курсивом контекст, а также встречавшиеся в контексте символы и их частоты.
Пусть текущий символ равен 'г', т.е. '?' = 'г', тогда процесс его кодирования будет выглядеть следующим образом.
Сначала рассматривается контекст 3-го порядка "ббв". Ранее он не встречался, поэтому кодер, ничего не послав на выход, переходит к анализу статистики для контекста 2-го порядка. В этом контексте ("бв") встречались символ 'а' и символ 'в', счетчики которых в соответствующей КМ равны 1 каждый, поэтому символ ухода кодируется с вероятностью 1/(2+1), где в знаменателе число 2 - это наблюдавшаяся частота появления контекста "бв", 1 - это значение счетчика символа ухода. В контексте 1-го порядка "в" дважды встречался символ 'а', который исключается (маскируется), один раз также исключаемый 'в' и один раз 'б', поэтому оценка вероятности ухода будет равна 1/(1+1). В КМ(0) символ 'г' также оценить нельзя, причем все имеющиеся в этой КМ символы 'а', 'б', 'в' исключаются, так как уже встречались нам в КМ более высокого порядка. Поэтому вероятность ухода получается равной 1. Цикл оценивания завершается на уровне КМ(-1), где 'г' к этому времени остается единственным до сих пор не попадавшимся символом, поэтому он получает вероятность 1 и кодируется посредством 0 битов. Таким образом, при использовании хорошего статистического кодировщика для представления 'г' потребуется в целом примерно 2.6 бита.
Перед обработкой следующего символа создается КМ для строки "ббв" и производится модификация счетчиков символа 'г' в созданной и во всех просмотренных КМ. В данном случае требуется изменение КМ всех порядков от 0 до N.
Табл. 3.2 демонстрирует оценки вероятностей, которые должны были быть использованы при кодировании символов алфавита {'а', 'б', 'в', 'г'} в текущей позиции.
Символ s | Последовательность оценок для КМ каждого порядка от 3 до -1 | Общая оценка вероятности q(s) | Представление требует битов | ||||
3 | 2 | 1 | 0 | -1 | |||
"ббв" | "бв" | "в" | "" | ||||
'а' | - | ![]() |
- | - | ![]() |
1.6 | |
'б' | - | ![]() |
![]() |
- | - | ![]() |
2.6 |
'в' | - | ![]() |
- | - | - | ![]() |
1.6 |
'г' | - | ![]() |
![]() |
1 | 1 | ![]() |
2.6 |
Алгоритм декодирования абсолютно симметричен алгоритму кодирования. После декодирования символа в текущей КМ проверяется, не является ли он символом ухода, если это так, то выполняется переход к КМ порядком ниже. Иначе считается, что исходный символ восстановлен, он записывается в декодированный поток и осуществляется переход к следующему шагу. Содержание процедур обновления счетчиков, создания новых контекстных моделей, прочих вспомогательных действий и последовательность их применения должны быть строго одинаковыми при кодировании и декодировании. Иначе возможна рассинхронизация копий модели кодера и декодера, что рано или поздно приведет к ошибочному декодированию какого-то символа. Начиная с этой позиции, вся оставшаяся часть сжатой последовательности будет разжата неправильно.
Разница между кодами символов, оценки вероятности которых одинаковы, достигается за счет того, что PPM-предсказатель передает кодировщику так называемые накопленные частоты (или накопленные вероятности) оцениваемого символа и его соседей или кодовые пространства символов. Так, например, для контекста "бв" из примера 2 можно составить табл. 3.3.
Символ | Частота | Оценка вероятности | Накопленная вероятность (оценка) | Кодовое пространство |
'а' | 1 | ![]() |
![]() |
[0 … 0.33) |
'б' | 0 | - | - | - |
'в' | 1 | ![]() |
![]() |
[0.33 … 0.66) |
'г' | 0 | - | - | - |
Уход | 1 | ![]() |
1 | [0.66 … 1) |
Хороший кодировщик должен отобразить символ s с оценкой вероятности q(s) в код длины , что и обеспечит сжатие всей обрабатываемой последовательности в целом.
В обобщенном виде алгоритм кодирования можно записать так.
/*инициализация контекста длины N (в смысле строки предыдущих символов), эта строка должна содержать N предыдущих символов, определяя набор активных контекстов длины o<=N */ context = ""; while ( ! DataFile.EOF() ){ c = DataFile.ReadSymbol(); // текущий символ order = N; // текущий порядок КМ success = 0; // успешность оценки в текущей КМ do{ // найдем КМ для контекста текущей длины CM = ContextModel.FindModel (context, order); /*попробуем найти текущий символ c в этой КМ, в CumFreq получим его накопленную частоту (или накопленную частоту символа ухода), в counter - ссылку на счетчик символа; флаг success указывает на отсутствие ухода */ success = CM.EvaluateSymbol (c, &CumFreq, counter); /*запомним в стеке КМ и указатель на счетчик для последующего обновления модели */ Stack.Push (CM, counter); // закодируем c или символ ухода StatCoder.Encode (CM, CumFreq, counter); order--; }while ( ! success ); /*обновим модель: добавим КМ в случае необходимости, изменим значения счетчиков и т.д. */ UpdateModel (Stack); // обновим контекст: сдвинем влево, справа добавим c MoveContext (c); }Пример 3.1.