Применение методов контекстного моделирования для сжатия данных опирается на
Под моделированием понимается построение модели информационного источника, породившего сжимаемые данные, а под кодированием - отображение обрабатываемых данных в сжатую форму представления на основании результатов моделирования (рис. 3.1). "Кодировщик" создает выходной поток, являющийся компактной формой представления обрабатываемой последовательности, на основании информации, поставляемой ему "моделировщиком".
Схема процесса сжатия данных в соответствии с концепцией универсальных моделирования и кодирования представлена на рис. 3.1
(рис 3.1) Схема процесса сжатия данных в соответствии с концепцией универсальных моделирования и кодированияСледует заметить, что понятие "кодирование" часто используют в широком смысле для обозначения всего процесса сжатия, т.е. включая моделирование в данном нами определении. Таким образом, необходимо различать понятия кодирования в широком смысле (весь процесс) и в узком (генерация потока кодов на основании информации модели). Понятие "статистическое кодирование" также используется, зачастую с сомнительной корректностью, для обозначения того или иного уровня кодирования. Во избежание путаницы ряд авторов применяет термин "энтропийное кодирование" для кодирования в узком смысле. Это наименование далеко от совершенства и встречает вполне обоснованную критику. Далее в этой главе процесс кодирования в широком смысле будем именовать "кодированием", а в узком смысле - "статистическим кодированием", или "собственно кодированием".
Из
Оценка вероятностей символов при моделировании производится на основании известной
Рассмотрим пример. Предположим, что мы сжимаем последовательность {'0','1'}, порожденную источником без памяти, и вероятности генерации символов следующие: p('0') = 0.4, p('1') = 0.6. Пусть наша модель дает такие оценки вероятностей: q('0') = 0.35, q('1') = 0.65. H источника равна
$$ - p('0')\log _2 p('0') - p('1')\log _2 p('1') =\\ = - 0.4\log _2 0.4 - 0.6\log _2 0.6 \approx 0.971\;бита$$.
Если подходить формально, то "
Казалось бы, что модель обеспечивает лучшее сжатие, чем это позволет p, то '0' следует кодировать $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.4}} \approx 1.332$$, а для '1' нужно отводить $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.6}} \approx 0.737$$ бита. Для оценок вероятностей q мы имеем $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.35}} \approx 1.515$$ бита и $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.65}} \approx 0.621$$ бита соответственно. При каждом кодировании на основании информации модели в случае '0' мы будем терять 1.515 - 1.322 = 0.193 бита, а в случае '1' выигрывать 0.737 - 0.621 = 0.116 бита. С учетом вероятностей появления символов средний проигрыш при каждом кодировании составит 0.4·0.193 - 0.6·0.116 = 0.008 бита.
Правильность
Осознание двойственной природы процесса сжатия позволяет осуществлять
Задача статистического кодирования была в целом успешно решена к началу 1980-х годов. Арифметический
В свете вышесказанного, повышение точности моделей является, фактически, единственным способом существенного улучшения сжатия.
Перед рассмотрением контекстных методов моделирования следует сказать о классификации стратегий моделирования
При статическом моделировании для любых обрабатываемых данных используется одна и та же модель. Иначе говоря, не производится
Полуадаптивное сжатие является развитием стратегии статического моделирования. В этом случае для сжатия заданной последовательности выбирается или строится модель на основании анализа именно обрабатываемых данных. Понятно, что
Адаптивное моделирование является естественной противоположностью статической стратегии. По мере кодирования модель изменяется по заданному алгоритму после сжатия каждого символа. Однозначность
Блочно-адаптивное моделирование можно рассматривать как частный случай адаптивной стратегии (или наоборот, что сути дела не меняет). В зависимости от конкретного алгоритма обновления модели, оценки вероятностей символов, метода статистического кодирования и самих данных изменение модели после обработки каждого символа может быть сопряжено со следующими неприятностями:
Поэтому обновление модели может выполняться после обработки целого блока символов, в общем случае переменной длины. Для обеспечения правильности разжатия декодер должен выполнять такую же последовательность действий по обновлению модели, что и
Понятно, что приведенная классификация является до некоторой степени абстрактной, и на практике часто используют
Итак, нам необходимо решить задачу оценки вероятностей появления символов в каждой позиции обрабатываемой последовательности. Для того чтобы разжатие произошло без потерь, мы можем пользоваться только той информацией, которая в полной мере известна как
Пожалуй, наиболее простой способ оценки реализуется с помощью полуадаптивного моделирования и заключается в предварительном подсчете безусловной частоты появления символов в сжимаемом блоке. Полученное
Анализ распространенных типов данных - например, тех же текстов на естественных языках, - выявляет сильную зависимость вероятности появления символов от непосредственно им предшествующих. Иначе говоря, большая часть данных, с которыми мы сталкиваемся, порождается источниками с памятью. Допустим, нам известно, что сжимаемый блок является текстом на русском языке. Если, например, строка из трех только что обработанных символов равна "_цы" (подчеркиванием здесь и далее обозначается пробел), то текущий символ скорее всего входит в следующую группу: 'г' ("цыган"), 'к' ("цыкать"), 'п' ("цыпочки"), 'ц' ("цыц"). Или, в случае анализа сразу нескольких слов, если предыдущая строка равна "Вставай,_проклятьем_заклейменный,", то продолжением явно будет "весь_мир_". Следовательно, учет зависимости частоты появления символа
(в общем случае - блока символов) от предыдущих должен давать более точные оценки и, в конечном счете, лучшее сжатие. Действительно, в случае посимвольного кодирования при использовании информации об одном непосредственно предшествующем символе достигается
Любопытно, что модели, оперирующие безусловными частотами и частотами в зависимости от одного предшествующего символа, дают примерно одинаковые результаты для всех европейских языков (за исключением, быть может, самых экзотических) - 4.5 и 3.6 бита соответственно.
Улучшение сжатия при учете предыдущих элементов (пикселов, сэмплов, отсчетов, чисел) отмечается и при обработке данных других распространенных типов:
Под контекстным моделированием будем понимать оценку вероятности появления символа (элемента, пиксела, сэмпла, отсчета и даже набора качественно разных объектов) в зависимости от непосредственно ему предшествующих, или контекста.
Заметим, что в быту понятие "контекст" обычно используется в глобальном значении - как совокупность символов (элементов), окружающих текущий обрабатываемый. Это контекст в широком смысле. Выделяют также "левосторонние" и "правосторонние" контексты, т.е. последовательности символов, непосредственно примыкающие к текущему символу слева и справа соответственно. Здесь и далее под контекстом будем понимать именно классический левосторонний: так, например, для последнего символа 'о' последовательности "…молоко…" контекстом является "…молок".
Если длина контекста ограничена, то такой подход будем называть контекстным моделированием ограниченного порядка (N. Например, при моделировании порядка 3 для последнего символа 'о' в последовательности "…молоко…" контекстом максимальной длины 3 является строка "лок". При сжатии этого символа под "текущими контекстами" могут пониматься "лок", "ок", "к", а также пустая строка "". Все эти контексты длины от N до 0 назовем активными контекстами в том смысле, что при оценке символа может быть использована накопленная для них
Далее вместо "контекст длины o, $$o \le N$$ /" мы будем обычно говорить "контекст порядка o".
В силу объективных причин - ограниченность вычислительных ресурсов - техника контекстного моделирования именно ограниченного порядка получила наибольшее развитие и распространение, поэтому далее под контекстным моделированием будем понимать именно ее. Дальнейшее изложение также учитывает специфику того, что контекстное моделирование практически всегда применяется как адаптивное.
Оценки вероятностей при контекстном моделировании строятся на основании обычных счетчиков частот, связанных с текущим контекстом. Если мы обработали строку "абсабвбабс", то для контекста "аб" счетчик символа 'c' равен двум (говорят, что символ 'c' появился в контексте "аб" два раза), символа 'в' - единице. На основании этой
В общем случае для каждого контекста конечной длины $$o \le N$$, встречаемого в обрабатываемой последовательности, создается контекстная модель КМ. Любая КМ включает в себя счетчики всех символов, встреченных в соответствующем ей контексте, т.е. сразу после строки контекста. После каждого появления какого-то символа s в рассматриваемом контексте производится увеличение значения счетчика символа s в соответствующей контексту КМ. Обычно счетчики инициализируются нулями. На практике счетчики обычно создаются по мере появления в заданном контексте новых символов, т.е. счетчиков ни разу не виденных в заданном контексте символов просто не существует.
Под порядком КМ будем понимать длину соответствующего ей контекста. Если порядок КМ равен o, то будем обозначать такую КМ как "КМ(o)".
Кроме обычных КМ, часто используют контекстную модель минус первого порядка КМ(-1), присваивающую одинаковую вероятность всем
Понятно, что для нулевого и минус первого порядка контекстная модель одна, а КМ большего порядка может быть несколько, вплоть до $$q^N,$$ где q - размер алфавита обрабатываемой последовательности. КМ(0) и КМ(-1) всегда активны.
Заметим, что часто не делается различий между понятием "контекст" и "контекстная модель". Авторы этой книги такое соглашение не поддерживают.
Часто говорят о "родительских" и "дочерних" контекстах. Для контекста "к" дочерними являются "ок" и "лк", поскольку они образованы сцеплением (
Совокупность КМ образует модель
Пример обработки строки "абсабвбабс" иллюстрирует сразу две проблемы контекстного моделирования:
Выше были приведены цифры, в соответствии с которыми при увеличении длины используемого контекста сжатие данных улучшается. К сожалению, при кодировании блоков типичной длины - единицы N, обеспечивают сравнительно низкую точность предсказания. Кроме того, хранение модели большого порядка требует много памяти.
Если в модели используются для оценки только КМ(N), то иногда такой подход называют "чистым" (
Действительно, реально используемые файлы обычно имеют сравнительно небольшой размер, поэтому для улучшения их сжатия необходимо учитывать оценки вероятностей, получаемые на основании
Рассмотрим модель произвольного порядка N. Если $$q(s_i |o)$$ есть вероятность, присваиваемая в активной КМ(o) символу $$s_i$$ алфавита сжимаемого потока, то смешанная вероятность $$q(s_i)$$ вычисляется в общем случае как
где w(o) - вес оценки КМ(o).
Оценка $$q(s_i |o)$$ обычно определяется через частоту символа $$s_i$$ по тривиальной формуле
$$q(s_i |o) = {f(s_i |o) \over f(o)}$$где $$f(s_i |o)$$ - частота появления символа $$s_i$$ в соответствующем контексте порядка o ;
$$f(o)$$ - общая частота появления соответствующего контекста порядка o в обработанной последовательности.
Заметим, что правильнее было бы писать не, скажем, $$f(s_i |o)$$, а $$f(s_i |C_{j(o)})$$, т.е. "частота появления символа $$s_i$$ в КМ порядка o с номером j(o) ", поскольку контекстных моделей порядка o может быть огромное количество. Но при сжатии каждого текущего символа мы рассматриваем только одну КМ для каждого порядка, т.к. контекст определяется непосредственно примыкающей слева к символу строкой определенной длины. Иначе говоря, для каждого символа мы имеем набор из N+1 активных контекстов длины от N до 0, каждому из которых однозначно соответствует только одна КМ, если она вообще есть. Поэтому здесь и далее используется сокращенная запись.
Если вес w(-1) > 0, то это гарантирует успешность кодирования любого символа входного потока, т.к. наличие КМ(-1) позволяет всегда получать ненулевую оценку вероятности и, соответственно, код конечной длины.
Различают модели с полным смешиванием (fully
Пример 1
Рассмотрим процесс оценки отмеченного на рис 3.2 стрелкой символа 'л', встретившегося в блоке "молочное_молоко". Считаем, что модель работает на уровне символов.
(рис 3.2) Пусть мы используем контекстное моделирование порядка 2 и делаем полное смешивание оценок
Для текущего символа 'л' имеются контексты "мо", "о" и пустой (нулевого порядка). К данному моменту для них накоплена
| Символы | 'м' | 'о' | 'л' | 'ч' | 'н' | 'е' | '_' | 'к' | |
|---|---|---|---|---|---|---|---|---|---|
| КМ порядка 0 (контекст "") | Частоты | 3 | 5 | 2 | 2 | 2 | 2 | 2 | 1 |
| Накопленные частоты | 3 | 8 | 10 | 12 | 14 | 16 | 18 | 19 | |
| КМ порядка 1 (контекст "о") | Частоты | - | - | 1 | 1 | - | 1 | - | - |
| Накопленные частоты | - | - | 1 | 2 | - | 3 | - | - | |
| КМ порядка 2("мо") | Частоты | - | - | 1 | - | - | - | - | - |
| Накопленные частоты | - | - | 1 | - | - | - | - | - |
Тогда оценка вероятности для символа 'л' будет равна
$$q('л') = 0.1 \cdot {2 \over {19}} + 0.3 \cdot {1 \over 3} + 0.6 \cdot {1 \over 1} = 0,71 $$В общем случае, для однозначного
Очевидно, что успех применения смешивания зависит от способа выбора весов w(o). Простой путь состоит в использовании заданного набора фиксированных весов КМ разных порядков при каждой оценке; этот способ был применен в примере 2. Естественно,
Техника неявного взвешивания связана с введением вспомогательного символа ухода (N, затем в определенной последовательности осуществляется переход к контекстным моделям меньших порядков.
Естественно, статистическое
Техника контекстного моделирования
Перед собственно рассмотрением алгоритмов необходимо сделать замечание о корректности используемой терминологии. На протяжении примерно 10 лет - с середины 1980-х годов до середины 1990-х - под
Ниже будет описан некий обобщенный алгоритм , а затем особенности конкретных распространенных схем.
Как и в случае многих других контекстных методов, для каждого контекста, встречаемого в обрабатываемой последовательности, создается своя контекстная модель КМ. При этом под контекстом понимается последовательность элементов одного типа - символов, пикселов, чисел, но не набор разнородных объектов. Далее вместо слова "элемент" мы будем использовать "символ". Каждая КМ включает в себя счетчики всех символов, встреченных в соответствующем контексте.
относится к адаптивным методам моделирования. Исходно
В используется неявное взвешивание оценок. Попытка оценки символа начинается с КМ(N), где N является параметром алгоритма и называется порядком
Фактически, вероятность ухода - это суммарная вероятность всех
Вообще говоря, способ моделирования источника с помощью классических алгоритмов
N, т.е. вероятность генерации символа зависит от N предыдущих символов и только от них;Таким образом, механизм уходов первоначально рассматривался лишь как вспомогательный прием, позволяющий решить проблему кодирования символов, ни разу не встречавшихся в контексте порядка N. В идеале, достигаемом после обработки достаточно N происходить не должно. Иначе говоря, причисление классических алгоритмов
При сжатии
Если символ s обрабатывается с использованием N, то, как мы уже отмечали, в первую очередь рассматривается KM(N). Если она оценивает вероятность s числом, не равным нулю, то сама и используется для кодирования s. Иначе выдается сигнал в виде символа ухода, и на основе меньшей по порядку КМ(N-1) производится очередная попытка оценить вероятность s. Кодирование происходит через уход к КМ меньших порядков до тех пор, пока s не будет оценен. КМ(-1) гарантирует, что это в конце концов произойдет. Таким образом, каждый символ кодируется серией
Если в процессе оценки обнаруживается, что текущий рассматриваемый контекст встречается в первый раз, то для него создается KM(N).
При оценке вероятности символа в КМ порядка o < N можно исключить из рассмотрения все символы, которые содержатся в KM(0+1), поскольку ни один из них точно не является символом s. Для этого в текущей KM(o) нужно замаскировать, т.е. временно установить в ноль, значения счетчиков всех символов, имеющихся в КМ(o+1). Такая техника называется методом исключения (exclusion).
После собственно
Рассмотрим подробнее работу алгоритма
Пример 2
Имеется последовательность символов "абвавабввбббв" алфавита {'а', 'б', 'в', 'г'}, которая уже была закодирована. (см. рис. 3.3)
(рис 3.3) Пусть счетчик символа ухода равен 1 для всех КМ, при обновлении модели счетчики символов увеличиваются на 1 во всех активных КМ, применяется метод исключения, и максимальная длина контекста равна 3, т.е. N = 3.
Первоначально модель состоит из КМ(-1), в которой счетчики всех четырех
(рис 3.4) Состояние модели после обработки последовательности "абвавабввбббв"Пусть текущий символ равен 'г', т.е. '?' = 'г', тогда процесс его кодирования будет выглядеть следующим образом.
Сначала рассматривается контекст 3-го порядка "ббв". Ранее он не встречался, поэтому
Перед обработкой следующего символа создается КМ для строки "ббв" и производится модификация счетчиков символа 'г' в созданной и во всех просмотренных КМ. В данном случае требуется изменение КМ всех порядков от 0 до N.
Табл. 3.2 демонстрирует оценки вероятностей, которые должны были быть использованы при
| Символ s | Последовательность оценок для КМ каждого порядка от 3 до -1 | Общая оценка вероятности q(s) | Представление требует битов | ||||
| 3 | 2 | 1 | 0 | -1 | |||
| "ббв" | "бв" | "в" | "" | ||||
| 'а' | - | $${1 \over {2 + 1}}$$ | - | - | $${1 \over 3}$$ | 1.6 | |
| 'б' | - | $${1 \over {2 + 1}}$$ | $${1 \over {1 + 1}}$$ | - | - | $${1 \over 6}$$ | 2.6 |
| 'в' | - | $${1 \over {2 + 1}}$$ | - | - | - | $${1 \over 3}$$ | 1.6 |
| 'г' | - | $${1 \over {2 + 1}}$$ | $${1 \over {1 + 1}}$$ | 1 | 1 | $${1 \over 6}$$ | 2.6 |
Алгоритм
Разница между
| Символ | Частота | Оценка вероятности | Накопленная вероятность (оценка) | Кодовое пространство |
| 'а' | 1 | $${1 \over 3}$$ | $${1 \over 3}$$ | [0 … 0.33) |
| 'б' | 0 | - | - | - |
| 'в' | 1 | $${1 \over 3}$$ | $${2 \over 3}$$ | [0.33 … 0.66) |
| 'г' | 0 | - | - | - |
| Уход | 1 | $${1 \over 3}$$ | 1 | [0.66 … 1) |
Хороший кодировщик должен отобразить символ s с оценкой вероятности q(s) в код длины $$\log _2 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);
}
Рассмотрим основные моменты реализации компрессора для простейшего случая с порядком модели N = 1 без исключения символов. Будем также исходить из того, что статистическое кодирование выполняется арифметическим
При контекстном моделировании 1-го порядка нам не требуются сложные
В структуру контекстной модели ContextModel включим массив счетчиков count для всех возможных 256 символов. Для символа ухода введем в структуру КМ специальный счетчик TotFr, в котором будет содержаться сумма значений счетчиков всех обычных символов. Использование поля TotFr не обязательно, но позволит ускорить обработку данных.
С учетом сказанного
struct ContextModel{
int esc, TotFr;
int count[256];
};
ContextModel cm[257];
Если размер типа int равен 4 байтам, то нам потребуется не менее 257 кбайт памяти для хранения модели.
Опишем стек, в котором будут храниться указатели на требующие модификации КМ, а также
ContextModel *stack[2]; int SP, context [1]; //контекст вырождается в 1 символ
Больше никаких
Инициализацию модели будем выполнять в общей для
void init_model (void){
/*Так как cm является глобальной переменной, то значения
всех полей равны 0. Нам требуется только распределить
кодовое пространство в КМ(0) так, чтобы все символы,
включая символ ухода, всегда бы имели ненулевые оценки.
Пусть также символы будут равновероятными
*/
for ( int j = 0; j < 256; j++ )
cm[256].count[j] = 1;
cm[256].TotFr = 256;
/*Явно запишем, что в начале моделирования мы считаем
контекст равным 0. Число не имеет значения, лишь бы
кодер и декодер точно следовали принятым
соглашениям. Обратите на это внимание
*/
context [0] = 0;
SP = 0;
}
Функции обновления модели также будут общими для update_model производится rescale осуществляется масштабирование счетчиков. Необходимость масштабирования обусловлена особенностями типичных реализаций арифметического кодирования и заключается в делении значений счетчиков пополам при достижении суммы значений всех счетчиков TotFr+ некоторого порога. Подробнее об этом рассказано в пункте "Обновление счетчиков символов".
const int MAX_TotFr = 0x3fff;
void rescale (ContextModel *CM){
CM->TotFr = 0;
for (int i = 0; i < 256; i++){
/*обеспечим отличие от нуля значения
счетчика после масштабирования
*/
CM->count[i] -= CM->count[i] >> 1;
CM->TotFr += CM->count[i];
}
}
void update_model (int c){
while (SP) {
SP--;
if ((stack[SP]->TotFr + stack[SP]->esc) >= MAX_TotFr)
rescale (stack[SP]);
if (!stack[SP]->count[c])
/*в этом контексте это новый символ, увеличим
счетчик уходов
*/
stack[SP]->esc += 1;
stack[SP]->count[c] += 1;
stack[SP]->TotFr += 1;
}
}
Собственно . Эта функция управляет последовательностью действий при сжатии данных, вызывая вспомогательные процедуры в требуемом порядке, а также находит нужную КМ. Оценка текущего символа производится в функции encode_sym, которая передает результаты своей работы арифметическому
int encode_sym (ContextModel *CM, int c){
// КМ потребует инкремента счетчиков, запомним ее
stack [SP++] = CM;
if (CM->count[c]){
/*счетчик сжимаемого символа не равен нулю, тогда
его можно оценить в текущей КМ; найдем
накопленную частоту предыдущего в массиве count
символа
*/
int CumFreqUnder = 0;
for (int i = 0; i < c; i++)
CumFreqUnder += CM->count[i];
/*передадим описание кодового пространства,
занимаемого символом c, арифметическому кодеру
*/
AC.encode (CumFreqUnder, CM->count[c], CM->TotFr + CM->esc);
return 1; // возвращаемся в encode с победой
}else{
/*нужно уходить на КМ(0);
если текущий контекст 1-го порядка встретился первый
раз, то заранее известно, что его КМ пуста (все
счетчики равны нулю), и кодировать уход не только не
имеет смысла, но и нельзя, т.к. TotFr+esc = 0
*/
if (CM->esc)
AC.encode (CM->TotFr, CM->esc, CM->TotFr + CM->esc);
return 0; // закодировать символ не удалось
}
}
void encode (void){
int c, // текущий символ
success; // успешность кодирования символа в КМ
init_model ();
AC.StartEncode (); // проинициализируем арифм. кодер
while (( c = DataFile.ReadSymbol() ) != EOF) {
// попробуем закодировать в КМ(1)
success = encode_sym (cm[context[0]], c);
if (!success)
/*уходим на КМ(0), где любой символ получит
ненулевую оценку и будет закодирован
*/
encode_sym (cm[256], c);
update_model (c);
context [0] = c; // сдвинем контекст
}
// закодируем знак конца файла символом ухода с КМ(0)
AC.encode (cm[context[0]].TotFr, cm[context[0]].esc,
cm[context[0]].TotFr + cm[context[0]].esc);
AC.encode (cm[256].TotFr, cm[256].esc,
cm[256].TotFr + cm[256].esc);
// завершим работу арифметического кодера
AC.FinishEncode();
}
Реализация декодера выглядит аналогично. Внимания заслуживает разве что только процедура поиска символа по описанию его кодового пространства. Метод get_freq арифметического x, лежащее в диапазоне [CumFreqUnder, CumFreqUnder+CM->count[i]), т.е. CumFreqUnder <= x < CumFreqUnder+CM->count[i]. Поэтому искомым символом является i, для которого выполнится это условие.
int decode_sym (ContextModel *CM, int *c){
stack [SP++] = CM;
if (!CM->esc) return 0;
int cum_freq = AC.get_freq (CM->TotFr + CM->esc);
if (cum_freq < CM->TotFr){
/*символ был закодирован в этой КМ; найдем символ и
его точное кодовое пространство
*/
int CumFreqUnder = 0;
int i = 0;
for (;;){
if ( (CumFreqUnder + CM->count[i]) <= cum_freq)
CumFreqUnder += CM->count[i];
else break;
i++;
}
/*обновим состояние арифметического кодера на
основании точной накопленной частоты символа
*/
AC.decode_update (CumFreqUnder, CM->count[i], CM->TotFr + CM->esc);
*c = i;
return 1;
}else{
/*обновим состояние арифметического кодера на
основании точной накопленной частоты символа,
оказавшегося символом ухода
*/
AC.decode_update (CM->TotFr, CM->esc, CM->TotFr + CM->esc);
return 0;
}
}
void decode (void){
int c, success;
init_model ();
AC.StartDecode ();
for (;;){
success = decode_sym (cm[context[0]], c);
if (!success){
success = decode_sym (cm[256], c);
if (!success) break; //признак конца файла
}
update_model (c);
context [0] = c;
DataFile.WriteSymbol (c);
}
}
Характеристики созданного компрессора, названного , приведены в пункте "Производительность на оформлен в виде приложения 1.
На долю символов ухода обычно приходится порядка 30% и более от всех оценок, вычисляемых моделировщиком
Можно выделить два подхода к решению проблемы ОВУ: априорные методы, основанные на предположениях о природе сжимаемых данных, и адаптивные методы, которые пытаются приспособить оценку к данным. Понятно, что первые призваны обеспечить хороший коэффициент сжатия при обработке типичных данных в сочетании с высокой скоростью вычислений, а вторые ориентированы на обеспечение максимально возможной степени сжатия.
Введем обозначения:
C - общее число просмотров контекста, т.е. сколько раз он встретился в обработанном
S - количество разных символов в контексте;
$$S^{(i)}$$ - количество таких разных символов, что они встречались в контексте ровно i раз;
$$E^{(x)}$$ - значение ОВУ по методу x.
Изобретатели алгоритма A и метод B. Использующие их алгоритмы PPMA и PPMB соответственно.
В дальнейшем было описано еще 5 априорных подходов к ОВУ: методы C, D, P, X и XC [8, 10, 17]. По аналогии с PPMA и PPMB, алгоритмы , применяющие методы C и D, получили названия PPMC и PPMD соответственно.
Идея методов и их сравнение представлены в табл. 3.4 и табл. 3.5.
| Метод | $$E^{(x)} = $$ |
|---|---|
| A | $${1 \over {C + 1}}$$ |
| B | $${{S - S^{(1)} } \over C}$$ |
| C | $${S \over {C + S}}$$ |
| D | $${S \over {2C}}$$ |
| P | $${{S^{(1)} } \over C} - {{S^{(2)} } \over {C^2 }} + {{S^{(3)} } \over {C^3 }} - \ldots $$ |
| X | $${{S^{(1)} } \over C}$$ |
| XC | $$\left\{ {\matrix{ {{{S^{(1)} } \over C},\quad при\quad 0 < S^{(1)} < C\quad } \cr {E^{(C)} ,\quad в\;прoтивнoм\;случае} \cr } } \right$$. |
Кстати, в примере 2 был использован метод A, а в компрессоре - метод С.
При реализации метода B воздерживаются от оценки символов до тех пор, пока они не появятся в текущем контексте более одного раза. Это достигается за счет P, X, XC базируются на предположении о том, что вероятность появления в обрабатываемых данных символа $$s_i $$ подчиняется закону Пуассона с параметром $$\lambda _i $$.
| Точность предсказания | |||||||
|---|---|---|---|---|---|---|---|
| Лучше | хуже | ||||||
| Тексты | XC | D | P | X | C | B | A |
| Двоичные файлы | C | X | P | XC | D | B | A |
Места в табл. 3.5 очень условны. Так, например, при сжатии текстов методы XC, D, P, X показывают весьма близкие результаты, и многое зависит от порядка модели и используемых для сравнения файлов. В большинстве случаев существенным является только отставание точности ОВУ по способам A и B от других методов.
C. Если текущий символ 'б', то точность его предсказания улучшится, останется неизменной или ухудшится?Чтобы улучшить оценку вероятности ухода, необходимо иметь такую модель оценки, которая бы адаптировалась к обрабатываемым данным. Подобный адаптивный механизм получил название
где $$f_i (esc)$$ - число наблюдавшихся уходов из контекстных моделей типа i ;
$$n_i$$ - число просмотров контекстных моделей типа i.
Вразумительные обоснования выбора этих характеристик и критериев "схожести" при отсутствии априорных знаний о характере сжимаемой последовательности дать сложно, поэтому известные алгоритмы адаптивной оценки базируются на эмпирическом анализе типовых данных.
Одна из самых ранних попыток реализации SEE известна как метод Z, а использующая его разновидность алгоритма [3.3]. Для точности описания этой техники SEE объект "контекст" ниже будет также именоваться "
Для нахождения ОВУ строятся так называемые контексты ухода (
Информация о фактическом количестве уходов и успешных кодирований во всех контекстных моделях, имеющих общий КУ, запоминается в счетчиках контекстной модели уходов КМУ, построенной для данного КУ. Эта информация определяет ОВУ для текущей КМ. ОВУ находится путем взвешивания оценок, которые дают три КМУ (КМУ порядка 2, 1 и 0), отвечающие характеристикам текущей КМ.
КУ порядка 2 наиболее точно соответствует текущей КМ, контексты ухода порядком ниже формируются главным образом путем выбрасывания части информации из полей КУ порядка 2. Компоненты КУ порядка 2 определяются в соответствии с табл. 3.6 [3.3].
| Номер поля | Размер в битах | Способ формирования значения поля | |
|---|---|---|---|
| Параметр и его значения | Значение поля | ||
| 1 | 2 | Порядок КМ | порядок КМ / 2 (с округлением до младшего); |
| 2 | 2 | Количество уходов из КМ | |
| 1 | 0 | ||
| 2 | 1 | ||
| 3 | 2 | ||
| > 3 | 3 | ||
| 3 | 3 | Количество успешных оценок в КМ | |
| 0 | 0 | ||
| 1 | 1 | ||
| 2 | 2 | ||
| 3,4 | 3 | ||
| 5,6 | 4 | ||
| 7,8,9 | 5 | ||
| 10,11,12 | 6 | ||
| > 12 | 7 | ||
| 4 | 9 | X1 = семь младших битов последнего (только что обработанного) символа X2 = шестой и пятый биты предпоследнего символа; т.е., если расписать байт как совокупность 8 битов xXXxxxxx, то это биты XX |
((X20x60) << 2) | X1 |
В состав КУ всех порядков входят поля 1, 2, 3. Для КУ порядка 1 поле 4 состоит из 8 битов и строится из шестых и пятых битов последних четырех обработанных символов. У КУ порядка 0 четвертое поле отсутствует. Очевидно, что алгоритм построения поля 4 для КУ порядков 1 и 2 призван улучшить предсказание ухода для текстов на английском языке в кодировке ASCII. Аналогичный прием, хотя и в не столь явном виде, используется в адаптивных методах ОВУ SEE-d1 и SEE-d2, рассмотренных ниже.
При взвешивании КМУ(n) используются следующие веса $$w_n$$
$${1 \over {w_n }} = e \cdot \log _2 \left( {{1 \over e}} \right) + (1 - e) \cdot \log _2 \left( {{1 \over {1 - e}}} \right)$$,
где e - ОВУ, которую дает данная взвешиваемая КМУ(n) ; формируется из фактического количества уходов и успешных кодирований в контекстных моделях, соответствующих этой КМУ, или, иначе, определяется наблюдавшейся частотой ухода из таких КМ.
Окончательная оценка:
$$E^{(Z)} = {{\sum\limits_{n = 0}^2 {e_n w_n } } \over {\sum\limits_{n = 0}^2 {w_n } }}$$.
После ОВУ выполняется поиск текущего символа среди имеющихся в КМ. По результатам поиска (символ найден или нет) обновляются счетчики соответствующих трех КМУ порядка 0, 1 и 2.
Применение методов контекстного моделирования для сжатия данных опирается на
Под моделированием понимается построение модели информационного источника, породившего сжимаемые данные, а под кодированием - отображение обрабатываемых данных в сжатую форму представления на основании результатов моделирования (рис. 3.1). "Кодировщик" создает выходной поток, являющийся компактной формой представления обрабатываемой последовательности, на основании информации, поставляемой ему "моделировщиком".
Схема процесса сжатия данных в соответствии с концепцией универсальных моделирования и кодирования представлена на рис. 3.1
(рис 3.1) Схема процесса сжатия данных в соответствии с концепцией универсальных моделирования и кодированияСледует заметить, что понятие "кодирование" часто используют в широком смысле для обозначения всего процесса сжатия, т.е. включая моделирование в данном нами определении. Таким образом, необходимо различать понятия кодирования в широком смысле (весь процесс) и в узком (генерация потока кодов на основании информации модели). Понятие "статистическое кодирование" также используется, зачастую с сомнительной корректностью, для обозначения того или иного уровня кодирования. Во избежание путаницы ряд авторов применяет термин "энтропийное кодирование" для кодирования в узком смысле. Это наименование далеко от совершенства и встречает вполне обоснованную критику. Далее в этой главе процесс кодирования в широком смысле будем именовать "кодированием", а в узком смысле - "статистическим кодированием", или "собственно кодированием".
Из
Оценка вероятностей символов при моделировании производится на основании известной
Рассмотрим пример. Предположим, что мы сжимаем последовательность {'0','1'}, порожденную источником без памяти, и вероятности генерации символов следующие: p('0') = 0.4, p('1') = 0.6. Пусть наша модель дает такие оценки вероятностей: q('0') = 0.35, q('1') = 0.65. H источника равна
$$ - p('0')\log _2 p('0') - p('1')\log _2 p('1') =\\ = - 0.4\log _2 0.4 - 0.6\log _2 0.6 \approx 0.971\;бита$$.
Если подходить формально, то "
Казалось бы, что модель обеспечивает лучшее сжатие, чем это позволет p, то '0' следует кодировать $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.4}} \approx 1.332$$, а для '1' нужно отводить $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.6}} \approx 0.737$$ бита. Для оценок вероятностей q мы имеем $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.35}} \approx 1.515$$ бита и $${\rm{ - log}}_{\rm{2}} {\rm{0}}{\rm{.65}} \approx 0.621$$ бита соответственно. При каждом кодировании на основании информации модели в случае '0' мы будем терять 1.515 - 1.322 = 0.193 бита, а в случае '1' выигрывать 0.737 - 0.621 = 0.116 бита. С учетом вероятностей появления символов средний проигрыш при каждом кодировании составит 0.4·0.193 - 0.6·0.116 = 0.008 бита.
Правильность
Осознание двойственной природы процесса сжатия позволяет осуществлять
Задача статистического кодирования была в целом успешно решена к началу 1980-х годов. Арифметический
В свете вышесказанного, повышение точности моделей является, фактически, единственным способом существенного улучшения сжатия.
Перед рассмотрением контекстных методов моделирования следует сказать о классификации стратегий моделирования
При статическом моделировании для любых обрабатываемых данных используется одна и та же модель. Иначе говоря, не производится
Полуадаптивное сжатие является развитием стратегии статического моделирования. В этом случае для сжатия заданной последовательности выбирается или строится модель на основании анализа именно обрабатываемых данных. Понятно, что
Адаптивное моделирование является естественной противоположностью статической стратегии. По мере кодирования модель изменяется по заданному алгоритму после сжатия каждого символа. Однозначность
Блочно-адаптивное моделирование можно рассматривать как частный случай адаптивной стратегии (или наоборот, что сути дела не меняет). В зависимости от конкретного алгоритма обновления модели, оценки вероятностей символов, метода статистического кодирования и самих данных изменение модели после обработки каждого символа может быть сопряжено со следующими неприятностями:
Поэтому обновление модели может выполняться после обработки целого блока символов, в общем случае переменной длины. Для обеспечения правильности разжатия декодер должен выполнять такую же последовательность действий по обновлению модели, что и
Понятно, что приведенная классификация является до некоторой степени абстрактной, и на практике часто используют
Итак, нам необходимо решить задачу оценки вероятностей появления символов в каждой позиции обрабатываемой последовательности. Для того чтобы разжатие произошло без потерь, мы можем пользоваться только той информацией, которая в полной мере известна как
Пожалуй, наиболее простой способ оценки реализуется с помощью полуадаптивного моделирования и заключается в предварительном подсчете безусловной частоты появления символов в сжимаемом блоке. Полученное
Анализ распространенных типов данных - например, тех же текстов на естественных языках, - выявляет сильную зависимость вероятности появления символов от непосредственно им предшествующих. Иначе говоря, большая часть данных, с которыми мы сталкиваемся, порождается источниками с памятью. Допустим, нам известно, что сжимаемый блок является текстом на русском языке. Если, например, строка из трех только что обработанных символов равна "_цы" (подчеркиванием здесь и далее обозначается пробел), то текущий символ скорее всего входит в следующую группу: 'г' ("цыган"), 'к' ("цыкать"), 'п' ("цыпочки"), 'ц' ("цыц"). Или, в случае анализа сразу нескольких слов, если предыдущая строка равна "Вставай,_проклятьем_заклейменный,", то продолжением явно будет "весь_мир_". Следовательно, учет зависимости частоты появления символа
(в общем случае - блока символов) от предыдущих должен давать более точные оценки и, в конечном счете, лучшее сжатие. Действительно, в случае посимвольного кодирования при использовании информации об одном непосредственно предшествующем символе достигается
Любопытно, что модели, оперирующие безусловными частотами и частотами в зависимости от одного предшествующего символа, дают примерно одинаковые результаты для всех европейских языков (за исключением, быть может, самых экзотических) - 4.5 и 3.6 бита соответственно.
Улучшение сжатия при учете предыдущих элементов (пикселов, сэмплов, отсчетов, чисел) отмечается и при обработке данных других распространенных типов:
Под контекстным моделированием будем понимать оценку вероятности появления символа (элемента, пиксела, сэмпла, отсчета и даже набора качественно разных объектов) в зависимости от непосредственно ему предшествующих, или контекста.
Заметим, что в быту понятие "контекст" обычно используется в глобальном значении - как совокупность символов (элементов), окружающих текущий обрабатываемый. Это контекст в широком смысле. Выделяют также "левосторонние" и "правосторонние" контексты, т.е. последовательности символов, непосредственно примыкающие к текущему символу слева и справа соответственно. Здесь и далее под контекстом будем понимать именно классический левосторонний: так, например, для последнего символа 'о' последовательности "…молоко…" контекстом является "…молок".
Если длина контекста ограничена, то такой подход будем называть контекстным моделированием ограниченного порядка (N. Например, при моделировании порядка 3 для последнего символа 'о' в последовательности "…молоко…" контекстом максимальной длины 3 является строка "лок". При сжатии этого символа под "текущими контекстами" могут пониматься "лок", "ок", "к", а также пустая строка "". Все эти контексты длины от N до 0 назовем активными контекстами в том смысле, что при оценке символа может быть использована накопленная для них
Далее вместо "контекст длины o, $$o \le N$$ /" мы будем обычно говорить "контекст порядка o".
В силу объективных причин - ограниченность вычислительных ресурсов - техника контекстного моделирования именно ограниченного порядка получила наибольшее развитие и распространение, поэтому далее под контекстным моделированием будем понимать именно ее. Дальнейшее изложение также учитывает специфику того, что контекстное моделирование практически всегда применяется как адаптивное.
Оценки вероятностей при контекстном моделировании строятся на основании обычных счетчиков частот, связанных с текущим контекстом. Если мы обработали строку "абсабвбабс", то для контекста "аб" счетчик символа 'c' равен двум (говорят, что символ 'c' появился в контексте "аб" два раза), символа 'в' - единице. На основании этой
В общем случае для каждого контекста конечной длины $$o \le N$$, встречаемого в обрабатываемой последовательности, создается контекстная модель КМ. Любая КМ включает в себя счетчики всех символов, встреченных в соответствующем ей контексте, т.е. сразу после строки контекста. После каждого появления какого-то символа s в рассматриваемом контексте производится увеличение значения счетчика символа s в соответствующей контексту КМ. Обычно счетчики инициализируются нулями. На практике счетчики обычно создаются по мере появления в заданном контексте новых символов, т.е. счетчиков ни разу не виденных в заданном контексте символов просто не существует.
Под порядком КМ будем понимать длину соответствующего ей контекста. Если порядок КМ равен o, то будем обозначать такую КМ как "КМ(o)".
Кроме обычных КМ, часто используют контекстную модель минус первого порядка КМ(-1), присваивающую одинаковую вероятность всем
Понятно, что для нулевого и минус первого порядка контекстная модель одна, а КМ большего порядка может быть несколько, вплоть до $$q^N,$$ где q - размер алфавита обрабатываемой последовательности. КМ(0) и КМ(-1) всегда активны.
Заметим, что часто не делается различий между понятием "контекст" и "контекстная модель". Авторы этой книги такое соглашение не поддерживают.
Часто говорят о "родительских" и "дочерних" контекстах. Для контекста "к" дочерними являются "ок" и "лк", поскольку они образованы сцеплением (
Совокупность КМ образует модель
Пример обработки строки "абсабвбабс" иллюстрирует сразу две проблемы контекстного моделирования:
Выше были приведены цифры, в соответствии с которыми при увеличении длины используемого контекста сжатие данных улучшается. К сожалению, при кодировании блоков типичной длины - единицы N, обеспечивают сравнительно низкую точность предсказания. Кроме того, хранение модели большого порядка требует много памяти.
Если в модели используются для оценки только КМ(N), то иногда такой подход называют "чистым" (
Действительно, реально используемые файлы обычно имеют сравнительно небольшой размер, поэтому для улучшения их сжатия необходимо учитывать оценки вероятностей, получаемые на основании
Рассмотрим модель произвольного порядка N. Если $$q(s_i |o)$$ есть вероятность, присваиваемая в активной КМ(o) символу $$s_i$$ алфавита сжимаемого потока, то смешанная вероятность $$q(s_i)$$ вычисляется в общем случае как
где w(o) - вес оценки КМ(o).
Оценка $$q(s_i |o)$$ обычно определяется через частоту символа $$s_i$$ по тривиальной формуле
$$q(s_i |o) = {f(s_i |o) \over f(o)}$$где $$f(s_i |o)$$ - частота появления символа $$s_i$$ в соответствующем контексте порядка o ;
$$f(o)$$ - общая частота появления соответствующего контекста порядка o в обработанной последовательности.
Заметим, что правильнее было бы писать не, скажем, $$f(s_i |o)$$, а $$f(s_i |C_{j(o)})$$, т.е. "частота появления символа $$s_i$$ в КМ порядка o с номером j(o) ", поскольку контекстных моделей порядка o может быть огромное количество. Но при сжатии каждого текущего символа мы рассматриваем только одну КМ для каждого порядка, т.к. контекст определяется непосредственно примыкающей слева к символу строкой определенной длины. Иначе говоря, для каждого символа мы имеем набор из N+1 активных контекстов длины от N до 0, каждому из которых однозначно соответствует только одна КМ, если она вообще есть. Поэтому здесь и далее используется сокращенная запись.
Если вес w(-1) > 0, то это гарантирует успешность кодирования любого символа входного потока, т.к. наличие КМ(-1) позволяет всегда получать ненулевую оценку вероятности и, соответственно, код конечной длины.
Различают модели с полным смешиванием (fully
Пример 1
Рассмотрим процесс оценки отмеченного на рис 3.2 стрелкой символа 'л', встретившегося в блоке "молочное_молоко". Считаем, что модель работает на уровне символов.
(рис 3.2) Пусть мы используем контекстное моделирование порядка 2 и делаем полное смешивание оценок
Для текущего символа 'л' имеются контексты "мо", "о" и пустой (нулевого порядка). К данному моменту для них накоплена
| Символы | 'м' | 'о' | 'л' | 'ч' | 'н' | 'е' | '_' | 'к' | |
|---|---|---|---|---|---|---|---|---|---|
| КМ порядка 0 (контекст "") | Частоты | 3 | 5 | 2 | 2 | 2 | 2 | 2 | 1 |
| Накопленные частоты | 3 | 8 | 10 | 12 | 14 | 16 | 18 | 19 | |
| КМ порядка 1 (контекст "о") | Частоты | - | - | 1 | 1 | - | 1 | - | - |
| Накопленные частоты | - | - | 1 | 2 | - | 3 | - | - | |
| КМ порядка 2("мо") | Частоты | - | - | 1 | - | - | - | - | - |
| Накопленные частоты | - | - | 1 | - | - | - | - | - |
Тогда оценка вероятности для символа 'л' будет равна
$$q('л') = 0.1 \cdot {2 \over {19}} + 0.3 \cdot {1 \over 3} + 0.6 \cdot {1 \over 1} = 0,71 $$В общем случае, для однозначного
Очевидно, что успех применения смешивания зависит от способа выбора весов w(o). Простой путь состоит в использовании заданного набора фиксированных весов КМ разных порядков при каждой оценке; этот способ был применен в примере 2. Естественно,
Техника неявного взвешивания связана с введением вспомогательного символа ухода (N, затем в определенной последовательности осуществляется переход к контекстным моделям меньших порядков.
Естественно, статистическое
Техника контекстного моделирования
Перед собственно рассмотрением алгоритмов необходимо сделать замечание о корректности используемой терминологии. На протяжении примерно 10 лет - с середины 1980-х годов до середины 1990-х - под
Ниже будет описан некий обобщенный алгоритм , а затем особенности конкретных распространенных схем.
Как и в случае многих других контекстных методов, для каждого контекста, встречаемого в обрабатываемой последовательности, создается своя контекстная модель КМ. При этом под контекстом понимается последовательность элементов одного типа - символов, пикселов, чисел, но не набор разнородных объектов. Далее вместо слова "элемент" мы будем использовать "символ". Каждая КМ включает в себя счетчики всех символов, встреченных в соответствующем контексте.
относится к адаптивным методам моделирования. Исходно
В используется неявное взвешивание оценок. Попытка оценки символа начинается с КМ(N), где N является параметром алгоритма и называется порядком
Фактически, вероятность ухода - это суммарная вероятность всех
Вообще говоря, способ моделирования источника с помощью классических алгоритмов
N, т.е. вероятность генерации символа зависит от N предыдущих символов и только от них;Таким образом, механизм уходов первоначально рассматривался лишь как вспомогательный прием, позволяющий решить проблему кодирования символов, ни разу не встречавшихся в контексте порядка N. В идеале, достигаемом после обработки достаточно N происходить не должно. Иначе говоря, причисление классических алгоритмов
При сжатии
Если символ s обрабатывается с использованием N, то, как мы уже отмечали, в первую очередь рассматривается KM(N). Если она оценивает вероятность s числом, не равным нулю, то сама и используется для кодирования s. Иначе выдается сигнал в виде символа ухода, и на основе меньшей по порядку КМ(N-1) производится очередная попытка оценить вероятность s. Кодирование происходит через уход к КМ меньших порядков до тех пор, пока s не будет оценен. КМ(-1) гарантирует, что это в конце концов произойдет. Таким образом, каждый символ кодируется серией
Если в процессе оценки обнаруживается, что текущий рассматриваемый контекст встречается в первый раз, то для него создается KM(N).
При оценке вероятности символа в КМ порядка o < N можно исключить из рассмотрения все символы, которые содержатся в KM(0+1), поскольку ни один из них точно не является символом s. Для этого в текущей KM(o) нужно замаскировать, т.е. временно установить в ноль, значения счетчиков всех символов, имеющихся в КМ(o+1). Такая техника называется методом исключения (exclusion).
После собственно
Рассмотрим подробнее работу алгоритма
Пример 2
Имеется последовательность символов "абвавабввбббв" алфавита {'а', 'б', 'в', 'г'}, которая уже была закодирована. (см. рис. 3.3)
(рис 3.3) Пусть счетчик символа ухода равен 1 для всех КМ, при обновлении модели счетчики символов увеличиваются на 1 во всех активных КМ, применяется метод исключения, и максимальная длина контекста равна 3, т.е. N = 3.
Первоначально модель состоит из КМ(-1), в которой счетчики всех четырех
(рис 3.4) Состояние модели после обработки последовательности "абвавабввбббв"Пусть текущий символ равен 'г', т.е. '?' = 'г', тогда процесс его кодирования будет выглядеть следующим образом.
Сначала рассматривается контекст 3-го порядка "ббв". Ранее он не встречался, поэтому
Перед обработкой следующего символа создается КМ для строки "ббв" и производится модификация счетчиков символа 'г' в созданной и во всех просмотренных КМ. В данном случае требуется изменение КМ всех порядков от 0 до N.
Табл. 3.2 демонстрирует оценки вероятностей, которые должны были быть использованы при
| Символ s | Последовательность оценок для КМ каждого порядка от 3 до -1 | Общая оценка вероятности q(s) | Представление требует битов | ||||
| 3 | 2 | 1 | 0 | -1 | |||
| "ббв" | "бв" | "в" | "" | ||||
| 'а' | - | $${1 \over {2 + 1}}$$ | - | - | $${1 \over 3}$$ | 1.6 | |
| 'б' | - | $${1 \over {2 + 1}}$$ | $${1 \over {1 + 1}}$$ | - | - | $${1 \over 6}$$ | 2.6 |
| 'в' | - | $${1 \over {2 + 1}}$$ | - | - | - | $${1 \over 3}$$ | 1.6 |
| 'г' | - | $${1 \over {2 + 1}}$$ | $${1 \over {1 + 1}}$$ | 1 | 1 | $${1 \over 6}$$ | 2.6 |
Алгоритм
Разница между
| Символ | Частота | Оценка вероятности | Накопленная вероятность (оценка) | Кодовое пространство |
| 'а' | 1 | $${1 \over 3}$$ | $${1 \over 3}$$ | [0 … 0.33) |
| 'б' | 0 | - | - | - |
| 'в' | 1 | $${1 \over 3}$$ | $${2 \over 3}$$ | [0.33 … 0.66) |
| 'г' | 0 | - | - | - |
| Уход | 1 | $${1 \over 3}$$ | 1 | [0.66 … 1) |
Хороший кодировщик должен отобразить символ s с оценкой вероятности q(s) в код длины $$\log _2 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);
}
Рассмотрим основные моменты реализации компрессора для простейшего случая с порядком модели N = 1 без исключения символов. Будем также исходить из того, что статистическое кодирование выполняется арифметическим
При контекстном моделировании 1-го порядка нам не требуются сложные
В структуру контекстной модели ContextModel включим массив счетчиков count для всех возможных 256 символов. Для символа ухода введем в структуру КМ специальный счетчик TotFr, в котором будет содержаться сумма значений счетчиков всех обычных символов. Использование поля TotFr не обязательно, но позволит ускорить обработку данных.
С учетом сказанного
struct ContextModel{
int esc, TotFr;
int count[256];
};
ContextModel cm[257];
Если размер типа int равен 4 байтам, то нам потребуется не менее 257 кбайт памяти для хранения модели.
Опишем стек, в котором будут храниться указатели на требующие модификации КМ, а также
ContextModel *stack[2]; int SP, context [1]; //контекст вырождается в 1 символ
Больше никаких
Инициализацию модели будем выполнять в общей для
void init_model (void){
/*Так как cm является глобальной переменной, то значения
всех полей равны 0. Нам требуется только распределить
кодовое пространство в КМ(0) так, чтобы все символы,
включая символ ухода, всегда бы имели ненулевые оценки.
Пусть также символы будут равновероятными
*/
for ( int j = 0; j < 256; j++ )
cm[256].count[j] = 1;
cm[256].TotFr = 256;
/*Явно запишем, что в начале моделирования мы считаем
контекст равным 0. Число не имеет значения, лишь бы
кодер и декодер точно следовали принятым
соглашениям. Обратите на это внимание
*/
context [0] = 0;
SP = 0;
}
Функции обновления модели также будут общими для update_model производится rescale осуществляется масштабирование счетчиков. Необходимость масштабирования обусловлена особенностями типичных реализаций арифметического кодирования и заключается в делении значений счетчиков пополам при достижении суммы значений всех счетчиков TotFr+ некоторого порога. Подробнее об этом рассказано в пункте "Обновление счетчиков символов".
const int MAX_TotFr = 0x3fff;
void rescale (ContextModel *CM){
CM->TotFr = 0;
for (int i = 0; i < 256; i++){
/*обеспечим отличие от нуля значения
счетчика после масштабирования
*/
CM->count[i] -= CM->count[i] >> 1;
CM->TotFr += CM->count[i];
}
}
void update_model (int c){
while (SP) {
SP--;
if ((stack[SP]->TotFr + stack[SP]->esc) >= MAX_TotFr)
rescale (stack[SP]);
if (!stack[SP]->count[c])
/*в этом контексте это новый символ, увеличим
счетчик уходов
*/
stack[SP]->esc += 1;
stack[SP]->count[c] += 1;
stack[SP]->TotFr += 1;
}
}
Собственно . Эта функция управляет последовательностью действий при сжатии данных, вызывая вспомогательные процедуры в требуемом порядке, а также находит нужную КМ. Оценка текущего символа производится в функции encode_sym, которая передает результаты своей работы арифметическому
int encode_sym (ContextModel *CM, int c){
// КМ потребует инкремента счетчиков, запомним ее
stack [SP++] = CM;
if (CM->count[c]){
/*счетчик сжимаемого символа не равен нулю, тогда
его можно оценить в текущей КМ; найдем
накопленную частоту предыдущего в массиве count
символа
*/
int CumFreqUnder = 0;
for (int i = 0; i < c; i++)
CumFreqUnder += CM->count[i];
/*передадим описание кодового пространства,
занимаемого символом c, арифметическому кодеру
*/
AC.encode (CumFreqUnder, CM->count[c], CM->TotFr + CM->esc);
return 1; // возвращаемся в encode с победой
}else{
/*нужно уходить на КМ(0);
если текущий контекст 1-го порядка встретился первый
раз, то заранее известно, что его КМ пуста (все
счетчики равны нулю), и кодировать уход не только не
имеет смысла, но и нельзя, т.к. TotFr+esc = 0
*/
if (CM->esc)
AC.encode (CM->TotFr, CM->esc, CM->TotFr + CM->esc);
return 0; // закодировать символ не удалось
}
}
void encode (void){
int c, // текущий символ
success; // успешность кодирования символа в КМ
init_model ();
AC.StartEncode (); // проинициализируем арифм. кодер
while (( c = DataFile.ReadSymbol() ) != EOF) {
// попробуем закодировать в КМ(1)
success = encode_sym (cm[context[0]], c);
if (!success)
/*уходим на КМ(0), где любой символ получит
ненулевую оценку и будет закодирован
*/
encode_sym (cm[256], c);
update_model (c);
context [0] = c; // сдвинем контекст
}
// закодируем знак конца файла символом ухода с КМ(0)
AC.encode (cm[context[0]].TotFr, cm[context[0]].esc,
cm[context[0]].TotFr + cm[context[0]].esc);
AC.encode (cm[256].TotFr, cm[256].esc,
cm[256].TotFr + cm[256].esc);
// завершим работу арифметического кодера
AC.FinishEncode();
}
Реализация декодера выглядит аналогично. Внимания заслуживает разве что только процедура поиска символа по описанию его кодового пространства. Метод get_freq арифметического x, лежащее в диапазоне [CumFreqUnder, CumFreqUnder+CM->count[i]), т.е. CumFreqUnder <= x < CumFreqUnder+CM->count[i]. Поэтому искомым символом является i, для которого выполнится это условие.
int decode_sym (ContextModel *CM, int *c){
stack [SP++] = CM;
if (!CM->esc) return 0;
int cum_freq = AC.get_freq (CM->TotFr + CM->esc);
if (cum_freq < CM->TotFr){
/*символ был закодирован в этой КМ; найдем символ и
его точное кодовое пространство
*/
int CumFreqUnder = 0;
int i = 0;
for (;;){
if ( (CumFreqUnder + CM->count[i]) <= cum_freq)
CumFreqUnder += CM->count[i];
else break;
i++;
}
/*обновим состояние арифметического кодера на
основании точной накопленной частоты символа
*/
AC.decode_update (CumFreqUnder, CM->count[i], CM->TotFr + CM->esc);
*c = i;
return 1;
}else{
/*обновим состояние арифметического кодера на
основании точной накопленной частоты символа,
оказавшегося символом ухода
*/
AC.decode_update (CM->TotFr, CM->esc, CM->TotFr + CM->esc);
return 0;
}
}
void decode (void){
int c, success;
init_model ();
AC.StartDecode ();
for (;;){
success = decode_sym (cm[context[0]], c);
if (!success){
success = decode_sym (cm[256], c);
if (!success) break; //признак конца файла
}
update_model (c);
context [0] = c;
DataFile.WriteSymbol (c);
}
}
Характеристики созданного компрессора, названного , приведены в пункте "Производительность на оформлен в виде приложения 1.
На долю символов ухода обычно приходится порядка 30% и более от всех оценок, вычисляемых моделировщиком
Можно выделить два подхода к решению проблемы ОВУ: априорные методы, основанные на предположениях о природе сжимаемых данных, и адаптивные методы, которые пытаются приспособить оценку к данным. Понятно, что первые призваны обеспечить хороший коэффициент сжатия при обработке типичных данных в сочетании с высокой скоростью вычислений, а вторые ориентированы на обеспечение максимально возможной степени сжатия.
Введем обозначения:
C - общее число просмотров контекста, т.е. сколько раз он встретился в обработанном
S - количество разных символов в контексте;
$$S^{(i)}$$ - количество таких разных символов, что они встречались в контексте ровно i раз;
$$E^{(x)}$$ - значение ОВУ по методу x.
Изобретатели алгоритма A и метод B. Использующие их алгоритмы PPMA и PPMB соответственно.
В дальнейшем было описано еще 5 априорных подходов к ОВУ: методы C, D, P, X и XC [8, 10, 17]. По аналогии с PPMA и PPMB, алгоритмы , применяющие методы C и D, получили названия PPMC и PPMD соответственно.
Идея методов и их сравнение представлены в табл. 3.4 и табл. 3.5.
| Метод | $$E^{(x)} = $$ |
|---|---|
| A | $${1 \over {C + 1}}$$ |
| B | $${{S - S^{(1)} } \over C}$$ |
| C | $${S \over {C + S}}$$ |
| D | $${S \over {2C}}$$ |
| P | $${{S^{(1)} } \over C} - {{S^{(2)} } \over {C^2 }} + {{S^{(3)} } \over {C^3 }} - \ldots $$ |
| X | $${{S^{(1)} } \over C}$$ |
| XC | $$\left\{ {\matrix{ {{{S^{(1)} } \over C},\quad при\quad 0 < S^{(1)} < C\quad } \cr {E^{(C)} ,\quad в\;прoтивнoм\;случае} \cr } } \right$$. |
Кстати, в примере 2 был использован метод A, а в компрессоре - метод С.
При реализации метода B воздерживаются от оценки символов до тех пор, пока они не появятся в текущем контексте более одного раза. Это достигается за счет P, X, XC базируются на предположении о том, что вероятность появления в обрабатываемых данных символа $$s_i $$ подчиняется закону Пуассона с параметром $$\lambda _i $$.
| Точность предсказания | |||||||
|---|---|---|---|---|---|---|---|
| Лучше | хуже | ||||||
| Тексты | XC | D | P | X | C | B | A |
| Двоичные файлы | C | X | P | XC | D | B | A |
Места в табл. 3.5 очень условны. Так, например, при сжатии текстов методы XC, D, P, X показывают весьма близкие результаты, и многое зависит от порядка модели и используемых для сравнения файлов. В большинстве случаев существенным является только отставание точности ОВУ по способам A и B от других методов.
C. Если текущий символ 'б', то точность его предсказания улучшится, останется неизменной или ухудшится?Чтобы улучшить оценку вероятности ухода, необходимо иметь такую модель оценки, которая бы адаптировалась к обрабатываемым данным. Подобный адаптивный механизм получил название
где $$f_i (esc)$$ - число наблюдавшихся уходов из контекстных моделей типа i ;
$$n_i$$ - число просмотров контекстных моделей типа i.
Вразумительные обоснования выбора этих характеристик и критериев "схожести" при отсутствии априорных знаний о характере сжимаемой последовательности дать сложно, поэтому известные алгоритмы адаптивной оценки базируются на эмпирическом анализе типовых данных.
Одна из самых ранних попыток реализации SEE известна как метод Z, а использующая его разновидность алгоритма [3.3]. Для точности описания этой техники SEE объект "контекст" ниже будет также именоваться "
Для нахождения ОВУ строятся так называемые контексты ухода (
Информация о фактическом количестве уходов и успешных кодирований во всех контекстных моделях, имеющих общий КУ, запоминается в счетчиках контекстной модели уходов КМУ, построенной для данного КУ. Эта информация определяет ОВУ для текущей КМ. ОВУ находится путем взвешивания оценок, которые дают три КМУ (КМУ порядка 2, 1 и 0), отвечающие характеристикам текущей КМ.
КУ порядка 2 наиболее точно соответствует текущей КМ, контексты ухода порядком ниже формируются главным образом путем выбрасывания части информации из полей КУ порядка 2. Компоненты КУ порядка 2 определяются в соответствии с табл. 3.6 [3.3].
| Номер поля | Размер в битах | Способ формирования значения поля | |
|---|---|---|---|
| Параметр и его значения | Значение поля | ||
| 1 | 2 | Порядок КМ | порядок КМ / 2 (с округлением до младшего); |
| 2 | 2 | Количество уходов из КМ | |
| 1 | 0 | ||
| 2 | 1 | ||
| 3 | 2 | ||
| > 3 | 3 | ||
| 3 | 3 | Количество успешных оценок в КМ | |
| 0 | 0 | ||
| 1 | 1 | ||
| 2 | 2 | ||
| 3,4 | 3 | ||
| 5,6 | 4 | ||
| 7,8,9 | 5 | ||
| 10,11,12 | 6 | ||
| > 12 | 7 | ||
| 4 | 9 | X1 = семь младших битов последнего (только что обработанного) символа X2 = шестой и пятый биты предпоследнего символа; т.е., если расписать байт как совокупность 8 битов xXXxxxxx, то это биты XX |
((X20x60) << 2) | X1 |
В состав КУ всех порядков входят поля 1, 2, 3. Для КУ порядка 1 поле 4 состоит из 8 битов и строится из шестых и пятых битов последних четырех обработанных символов. У КУ порядка 0 четвертое поле отсутствует. Очевидно, что алгоритм построения поля 4 для КУ порядков 1 и 2 призван улучшить предсказание ухода для текстов на английском языке в кодировке ASCII. Аналогичный прием, хотя и в не столь явном виде, используется в адаптивных методах ОВУ SEE-d1 и SEE-d2, рассмотренных ниже.
При взвешивании КМУ(n) используются следующие веса $$w_n$$
$${1 \over {w_n }} = e \cdot \log _2 \left( {{1 \over e}} \right) + (1 - e) \cdot \log _2 \left( {{1 \over {1 - e}}} \right)$$,
где e - ОВУ, которую дает данная взвешиваемая КМУ(n) ; формируется из фактического количества уходов и успешных кодирований в контекстных моделях, соответствующих этой КМУ, или, иначе, определяется наблюдавшейся частотой ухода из таких КМ.
Окончательная оценка:
$$E^{(Z)} = {{\sum\limits_{n = 0}^2 {e_n w_n } } \over {\sum\limits_{n = 0}^2 {w_n } }}$$.
После ОВУ выполняется поиск текущего символа среди имеющихся в КМ. По результатам поиска (символ найден или нет) обновляются счетчики соответствующих трех КМУ порядка 0, 1 и 2.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.