Я буду использовать наивный байесовский метод и логистическую регрессию для набора данных IMDB, чтобы предсказать тип обзора, т.е. положительный он или отрицательный. Кроме того, я добавлю еще несколько очень важных терминов. Предлагаю читателям также изучить фастай. Приступим.

❓ Что такое регуляризация

Fastai никогда не спорил о количестве параметров, которые необходимо учитывать при обучении модели. Fastai всегда поддерживает столько параметров, сколько вы хотите для обучения своей модели. Но стоит помнить, что если у вас возникли проблемы с обучением модели, добавление небольшого количества регуляризации может помочь ей обучаться быстрее (лучше! Я не буду утверждать). Согласно регуляризации, лучше наказывать те параметры, которые не равны нулю, потому что параметры с нулевым значением не влияют на потерю, потому что они равны нулю. Итак, есть два основных способа наказать ненулевые параметры:

  1. Мы можем изменить нашу функцию потерь, чтобы добавить этот квадратный штраф. Это известно как регуляризация L2. Это увеличит значение функции потерь, что приведет к большему обратному распространению и, следовательно, ненулевые необязательные веса будут стремиться к нулю. Вам нужно будет позаботиться об аспекте переобучения во время регуляризации.

  1. Мы можем изменить эту вещь, где мы сказали, что веса равны весам минус скорость обучения градиента (когда мы выполняем обратное распространение и оптимизируем наши градиенты, чтобы они соответствовали требованиям), чтобы также добавить 2aw. Это известно как регуляризация L1 или снижение веса. Это не повлияет напрямую на функцию потерь, но это будет вычтено из весов, и, следовательно, ненулевые необязательные параметры будут стремиться к нулю.

Давайте сделаем версию, которую PyTorch называет уменьшением веса, но это регуляризация L2.

Причина, по которой мы это делаем, заключается в том, что мы хотим наказать вещи, которые не равны нулю, чтобы сказать, не делайте этот параметр большим числом, если он сильно не способствует потере. Если можете, установите его на ноль, потому что установка как можно большего числа параметров на ноль означает, что обобщение будет лучше. Это все равно, что иметь меньшую сеть. Вот почему мы это делаем. Но это также может изменить способ обучения.

Если потеря обучения выше, чем потеря проверки, значит, вы не подходите. Так что нет смысла регуляризировать. Это всегда означало бы, что вам нужно больше параметров в вашей модели. Если вы переобучаете, это не обязательно означает, что регуляризация поможет, но попробовать определенно стоит.

Вы можете инициализировать значение уменьшения веса, используя fit_one_cycle () при подборе модели.

Подводя итог, мы можем построить очень точные модели, даже если они содержат множество параметров. Необязательно иметь меньше параметров, чтобы учиться лучше и лучше. Это основное понимание регуляризации. Я расскажу об этом больше в моих блогах с углубленным изучением.

❓Что такое отсев?

❓Что такое пакетная нормализация

❓ Что такое НЛП

NLP расшифровывается как обработка естественного языка. НЛП относится к любому моделированию, при котором мы работаем с текстом на естественном языке и обрабатываем его для получения результатов.

Чтобы лучше понять НЛП, я буду использовать набор данных IMDB. Это набор обзоров фильмов. Я буду использовать наивный байесовский метод, а затем - логистическую регрессию. Вы можете скачать набор данных, как показано ниже:

!wget http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
!gunzip aclImdb_v1.tar.gz
!tar -xvf aclImdb_v1.tar

В папках neg и pos находятся текстовые файлы. Я использую Google Colab для реализации данных.

PATH='/content/aclImdb/'
%ls {PATH}train/pos | head

Заглянем внутрь одного из текстовых файлов. Я буду использовать numpy, чтобы узнать текстовый файл.

%cd  /content/aclImdb/train/pos
np.loadtxt('10000_8.txt', dtype=np.str)

Наш следующий шаг - взять эти обзоры из папок вместе с их ярлыками и создать из него массив, чтобы мы могли легко получить доступ к данным. У Fastai есть удобный способ для этого.

trn,trn_y = texts_labels_from_folders(f'{PATH}train',names)
val,val_y = texts_labels_from_folders(f'{PATH}test',names)

Теперь вы можете проверить свои данные, как показано ниже.

trn[20000], trn_y[20000]
trn- will give you the review
trn_y- will return you the review label(0-negative review, 1- positive review)

Это наши данные. Итак, наша работа будет заключаться в том, чтобы сделать обзор фильма и спрогнозировать этикетку. При анализе данных мы не учитываем порядок слов. Мы будем рассматривать только наличие слова в обзоре. Обычно порядок слов имеет большое значение. Если перед чем-то стоит «не», то это «не» относится к этой вещи. Но в данном случае мы пытаемся предугадать, положительно или отрицательно что-то. Если вы часто видите слово «глупый» или «непонятный», возможно, это признак того, что это не очень хорошо. Если вы часто знаете слово «потрясающий», то, возможно, это хороший знак.

Идея состоит в том, что мы собираемся превратить это в нечто, называемое матрицей термин-документ, где для каждого документа (т.е. каждого обзора) мы просто собираемся создать список того, какие слова в нем, а не какие порядок их расположения.

  • Все слова в обзорах записаны и перечислены в следующем порядке: фильм, хороший, плохой. Словарь - это список всех уникальных слов, которые появляются. В этом случае ни одно из моих слов не встречается дважды. Это называется матрицей терминов и документов.
  • Мы добавили один, если функция присутствует в обзоре, и 0, если функция отсутствует.
  • Мы добавили еще один слой единиц, чтобы избежать появления бесконечного числа значений в случае, если конкретное слово не встречается в обзоре. Если я не написал такого слова, как «секс», ни в одном из своих обзоров, это не значит, что этого слова тоже не существует. Так что нам нужно позаботиться и об этом. Это особенно полезно, когда в качестве модели для прогнозирования отзывов мы используем Наивный пока. Мы обсудим это когда-нибудь.
  • Это просто набор слов (то есть, какие слова в нем). В нем есть «плохо», «есть», «фильм», «это». Итак, первое, что мы собираемся сделать, это превратить его в пакет словесных представлений. Причина, по которой это удобно для линейных моделей, заключается в том, что это полезная прямоугольная матрица, с которой мы можем производить вычисления. В частности, мы можем выполнить логистическую регрессию.
  • В Sklearn есть кое-что, что может автоматически создавать матрицу текстовых документов для нас - это известно как CountVectorizer. Прежде чем мы это сделаем, давайте разберемся с традиционными терминами НЛП.

❓ Что такое токенизация

Теперь в НЛП вам нужно превратить свой текст в список слов, и это называется токенизацией. Чем лучше вы токенизируете свои обзоры, тем лучше будут результаты.

veczr = CountVectorizer(tokenizer=tokenize)
trn_term_doc = veczr.fit_transform(trn)
val_term_doc = veczr.transform(val)
  • CountVectorizer преобразует коллекцию текстовых документов в матрицу счетчиков токенов (часть sklearn.feature_extraction.text).
  • fit_transform (trn) находит словарь в обучающем наборе. Он также преобразует обучающий набор в матрицу терм-документа. Поскольку мы должны применить то же преобразование к вашему набору проверки, в третьей строке используется только метод transform (val). trn_term_doc и являются разреженными матрицами. trn_term_doc[i] представляет учебный документ и содержит количество слов для каждого документа для каждого слова в словаре.
vocab = veczr.get_feature_names(); vocab[5000:5500]

  • get_feature_names () дает нам словарь. veczr.get_feature_names отображает целочисленный индекс слова на слово.
  • Слова - это целые числа, хранящиеся внутри словаря. Вы можете проверить целое число любого слова в словаре, как показано ниже:
veczr.vocabulary_['bad']
  • Когда мы создаем эту матрицу термин-документ, обучающий набор, у нас есть 25 000 строк, потому что есть 25 000 обзоров фильмов и 75 132 столбца, которые представляют собой количество уникальных слов.
trn_term_doc
<25000x75132 sparse matrix of type '<class 'numpy.int64'>'
     with 3749745 stored elements in Compressed Sparse Row format>
  • Сейчас в большинстве документов нет большей части из этих 75 132 слов. Поэтому мы не хотим хранить это как обычный массив в памяти. Потому что это будет очень расточительно. Поэтому вместо этого мы сохраняем его как разреженную матрицу. Что делает разреженная матрица, так это то, что она сохраняет ее как нечто, говорящее о местонахождении ненулевых элементов. Итак, он говорит: «Хорошо», появляется документ номер 11, слово номер 41, а в нем их 9. Документ номер 12, термин номер 23 встречается трижды и т. Д.
(11, 41) → 9
(12, 23) → 3
  • Теперь в CountVectorizer есть еще один атрибут - ngram_range. По умолчанию мы получаем униграммы, состоящие из отдельных слов. Но если мы скажем ngram_range=(1,3), это также даст нам биграммы и триграммы. Теперь вместо использования только отдельных слов мы можем комбинировать такие слова, как by hook and crook, fastai library и многие другие.
  • Таким образом, теперь выполняется то же самое, но после токенизации он не просто захватывает каждое слово и говорит, что это часть вашего словарного запаса, но каждые два слова рядом друг с другом и каждые три слова рядом друг с другом. И это оказывается очень полезным в использовании преимуществ набора слов, потому что теперь мы можем видеть разницу между not good, not bad и not terrible.
veczr =  CountVectorizer(ngram_range=(1,3), tokenizer=tokenize,
                         max_features=800000)
  • max_features используется для ограничения количества функций.
trn_term_doc.shape
= 25000, 800000

используя наивный байесовский

Итак, нам нужна вероятность того, что данный конкретный документ (у меня есть этот конкретный обзор IMDb), какова вероятность того, что его класс будет равен положительному или отрицательному. Итак, для этого конкретного обзора фильма, какова вероятность того, что его класс положительный. Таким образом, мы можем сказать, что это равно вероятности того, что мы получили этот конкретный обзор фильма, учитывая, что его класс положительный, умноженный на вероятность того, что класс любого обзора фильма является положительным, деленный на вероятность получения этого обзора конкретного фильма.

Это просто правило Байеса.

Таким образом, мы можем вычислить все эти вещи, но на самом деле мы хотим знать, является ли это более вероятным классом 0 или классом 1. А что, если бы мы взяли вероятность, принадлежащую классу 1, и разделили бы на вероятность, которая является классом 0. Что, если бы мы это сделали. что?

Итак, если это число более значимо, чем 1, то с большей вероятностью оно будет относиться к классу 1, если оно меньше 1, то с большей вероятностью будет к классу 0.

If we have to find probability of occurance of this feature given the review is positive p(f/1), then it is calculated as below:
Given this feature, what is the probability of finding it in positive review p(1/f) (out of three positive review) = 2/3
probability of selecting the positive review class = 1/2
probability of selecting the feature = 2/4
Probability of occurance of "this" in the positive reviews = ((2/3) * (1/2)) / (2/4) = 0.6667

По сути, чтобы определить положительный или отрицательный отзыв, выполните следующие действия:

  • Умножьте индивидуальные вероятности признаков в обзоре, рассматривая один раз положительный случай, а затем один раз отрицательный.
  • Разделите обе вероятности, будет ли отзыв положительным или отрицательным.
If I want to know about the review "movie is bad", then it can be calculates as below:
- Multiply the probabilites of features considering the review to be positive = 1*1*0.333
- Multiply the probabilites of features considering the review to be negative = 1*1*1
probability of movie review to be positive / probability of movie review to be negative = 0.333 < 1
Thus, the review is negative.

Вот как мы делаем вывод об обзоре.

Давайте сделаем это в коде Python.

def pr(y_i):
    p = x[y==y_i].sum(0)
    return (p+1) / ((y==y_i).sum()+1)
x=trn_term_doc
y=trn_y
r = np.log(pr(1)/pr(0))
b = np.log((y==1).mean() / (y==0).mean())
pre_preds = val_term_doc @ r.T + b
preds = pre_preds.T>0
(preds==val_y).mean()

  • Итак, здесь он написан как Python. Наша независимая переменная - это наша матрица терминов-документов, а наша зависимая переменная - это просто метки для y. Таким образом, используя numpy, этот x[y==1] будет захватывать строки, в которых зависимая переменная равна 1. Затем мы можем просуммировать их по строкам, чтобы получить общее количество слов для этой функции во всех документах плюс 1.
  • Тогда, конечно, более полезно вести журнал, потому что, если мы возьмем журнал, мы сможем складывать вещи вместе, а не умножать их вместе. И как только вы умножите достаточное количество этих вещей вместе, оно станет настолько близким к нулю, что у вас, вероятно, закончится число с плавающей запятой. Итак, берем журнал соотношений. Затем, как я уже сказал, мы умножаем это или с логарифмом добавляем это к отношению вероятностей всего класса. Затем, чтобы добавить в журнал соотношений классов, вы можете использовать + b.
  • Итак, мы получаем нечто, что очень похоже на логистическую регрессию. Но мы ничего не узнаем. Не с точки зрения SGD. Мы просто рассчитываем это, используя эту теоретическую модель. И это ~ 81% точности. Так что наивный Байес - это не что иное. Это нам кое-что дало.

Теперь, особенно для этой проблемы, все, что имеет значение, - появляется ли какое-либо слово или нет. Итак, мы можем заменить количество слов на единицу, если оно есть, и на -1, если оно не появляется. Другим способом мы могли бы преобразовать данные в двоичную форму.

pre_preds = val_term_doc.sign() @ r.T + b
preds = pre_preds.T>0
(preds==val_y).mean()
= 0.82623999999999997

Теперь мы будем использовать логистическую регрессию для той же проблемы и сравним результаты.

с использованием логистической регрессии

Наивный байесовский метод выдающийся с теоретической точки зрения, но на практике, вместо определения весов, почему бы нам не изучить их? Итак, давайте создадим логистическую регрессию и подберем некоторые коэффициенты. И это даст нам что-то с точно такой же функциональной формой, что и раньше, но теперь, вместо того, чтобы использовать теоретический r и теоретический b, мы собираемся вычислить эти две вещи на основе логистической регрессии. Мы - класс LogisticRegression, определенный в SkLearn.

m = LogisticRegression(C=1e8, dual=True)
m.fit(x, y)
preds = m.predict(val_term_doc)
(preds==val_y).mean()
  • dual = true работает как обходной путь, когда ваши данные больше, чем длинные.
  • C используется для регуляризации. Нам следует подумать о регуляризации, потому что у нас есть словарный запас на 75 000 слов для почти 25 000 обзоров. C = 1e8 выключает его из-за очень маленького числа; на функцию потерь вряд ли будет какое-либо влияние. C - величина, обратная сумме штрафа за регуляризацию. Мы используем L2-регуляризацию, потому что мы можем использовать только dual = true с L2-регуляризацией. Более того, L2 стоит по умолчанию.

Мы также можем запустить вышеуказанное решение для бинаризованной версии.

m = LogisticRegression(C=1e8, dual=True)
m.fit(trn_term_doc.sign(), y)
preds = m.predict(val_term_doc.sign())
(preds==val_y).mean()
= 0.85487999999999997

Теперь, чтобы включить регуляризацию, давайте объявим C = 0.1 и посмотрим на результаты.

m = LogisticRegression(C=0.1, dual=True)
m.fit(x, y)
preds = m.predict(val_term_doc)
(preds==val_y).mean()
= 0.88404000000000005

❓ FASTAI.NBSVM ++

sl=2000
md = TextClassifierData.from_bow(trn_term_doc, trn_y, val_term_doc, val_y, sl)
learner = md.dotprod_nb_learner()
learner.fit(0.02, 1, wds=1e-6, cycle_len=3)

  • sl = 2000 говорит, что нужно использовать 2000 уникальных слов.
  • TextClassifierData - это то, как мы получаем модель из набора слов. Это фастай.
  • Затем мы используем ученика наивного байесовского типа, чтобы изучать вещи.
  • И мы получаем точность примерно 92%.

Вот как мы используем традиционные и модернизированные методы для нашего набора данных.