1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-fastai-num-linalg-v2-zh

Клонировать/Скачать
3.md 21 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 30.11.2024 04:49 05baa78

Использование NMF и SVD для тематического моделирования

Тематическое моделирование — это хороший способ начать использовать матричные разложения. Мы начнём с термина «матрица документов»:

Источник: «Введение в информационный поиск» (http://player.slideplayer.com/15/4528582/#)

Мы можем разложить его на высокую и узкую матрицы (возможно, с диагональной матрицей посередине).

Обратите внимание, что это представление не учитывает порядок слов или структуру предложений. Это пример «мешка слов».

Мотивация

Рассмотрим крайний случай — использование внешнего произведения двух векторов для восстановления матрицы. Очевидно, что в большинстве случаев мы не сможем точно восстановить матрицу. Однако если у нас есть вектор, содержащий относительную частоту каждого слова во всех словах, и другой вектор, имеющий среднее количество слов в каждом документе, то произведение будет максимально приближено к исходному.

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

В этом курсе

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

Мы попытаемся использовать два разных матричных разложения: сингулярное разложение (SVD) и неотрицательное матричное разложение (NMF).

import numpy as np
from sklearn.datasets import fetch_20newsgroups
from sklearn import decomposition
from scipy import linalg
import matplotlib.pyplot as plt

%matplotlib inline
np.set_printoptions(suppress=True)

Дополнительные ресурсы

  • Источник данных: новостные группы представляют собой дискуссионные группы Usenet, которые были популярны до того, как Интернет действительно взлетел в 80-х и 90-х годах. Этот набор данных включает 18 000 сообщений новостных групп с 20 темами.
  • Книга Криса Мэннинга о матричном разложении и LSI (https://nlp.stanford.edu/IR-book/pdf/18lsi.pdf)
  • Детали усечённого SVD LSI от Sklearn (http://scikit-learn.org/stable/modules/decomposition.html#lsa)

Другие учебные пособия

  • Scikit-Learn: текстовая классификация вне ядра (http://scikit-learn.org/stable/auto_examples/applications/plot_out_of_core_classification.html): используется набор данных Reuters-21578 (помеченный примерно 100 категориями статей из агентства Рейтер), HashingVectorizer
  • Использование гуманитарных и социальных тематических моделей для анализа текста (https://de.dariah.eu/tatom/index.html): используются данные английской и французской литературы Джейн Остин, Шарлотты Бронте, Виктора Гюго и других

Создание данных

Scikit Learn поставляется со множеством встроенных наборов данных, а также инструментами для загрузки множества стандартных внешних наборов данных. Это отличный ресурс, включающий наборы данных о ценах на жилье в Бостоне, изображениях лиц, пятнах леса, диабете, раке молочной железы и т. д. Мы будем использовать набор данных новостных групп.

Новостные группы — это дискуссионные группы Usenet, популярные до того, как интернет действительно взлетел в 80-е и 90-е годы. Этот набор данных включает в себя 18 000 сообщений новостных групп с 20 различными темами.

categories = ['alt.atheism', 'talk.religion.misc', 'comp.graphics', 'sci.space']
remove = ('headers', 'footers', 'quotes')
newsgroups_train = fetch_20newsgroups(subset='train', categories=categories, remove=remove)
newsgroups_test = fetch_20newsgroups(subset='test', categories=categories, remove=remove)

newsgroups_train.filenames.shape, newsgroups_train.target.shape

# ((2034,), (2034,))

Давайте посмотрим на некоторые данные. Можете ли вы угадать, к какой категории относятся эти сообщения?

print("\n".join(newsgroups_train.data[:3]))

'''
Hi,

I've noticed that if you only save a model (with all your mapping planes
positioned carefully) to a .3DS file that when you reload it after restarting
3DS, they are given a default position and orientation.  But if you save
to a .PRJ file their positions/orientation are preserved.  Does anyone
know why this information is not stored in the .3DS file?  Nothing is
explicitly said in the manual about saving texture rules in the .PRJ file. 
I'd like to be able to read the texture rule information, does anyone have 
the format for the .PRJ file?

Is the .CEL file format available from somewhere?

Rych


Seems to be, barring evidence to the contrary, that Koresh was simply
another deranged fanatic who thought it neccessary to take a whole bunch of
folks with him, children and all, to satisfy his delusional mania. Jim
Jones, circa 1993.


Nope - fruitcakes like Koresh have been demonstrating such evil corruption
for centuries.

 >In article <1993Apr19.020359.26996@sq.sq.com>, msb@sq.sq.com (Mark Brader) 

MB>                                                             So the
MB> 1970 figure seems unlikely to actually be anything but a perijove.

JG>Sorry, _perijoves_...I'm not used to talking this language.

Couldn't we just say periapsis or apoapsis?
'''

Подсказка: определение периджове — это ближайшая точка на орбите спутника Юпитера.

np.array(newsgroups_train.target_names)[newsgroups_train.target[:3]]

'''
array(['comp.graphics', 'talk.religion.misc', 'sci.space'], 
      dtype='<U18')
'''

Атрибут target представляет собой целочисленный индекс категории.

newsgroups_train.target[:10]

# array([1, 3, 2, 0, 2, 0, 2, 1, 2, 1])

num_topics, num_top_words = 6, 8

Далее scikit learn предоставляет метод извлечения всех слов. TF-IDF

Метод TF-IDF (Term Frequency — Inverse Document Frequency) — это метод нормированного подсчёта частоты терминов, который учитывает частоту появления термина в документе и обратную частоту документа.

TF = (частота термина t в документе) / (общее количество слов в документе).

IDF = log (количество документов / количество документов, содержащих термин t).

vectorizer_tfidf = TfidfVectorizer(stop_words='english')
vectors_tfidf = vectorizer_tfidf.fit_transform(newsgroups_train.data) # (documents, vocab)

W1 = clf.fit_transform(vectors_tfidf)
H1 = clf.components_

show_topics(H1)

['Люди просто думают, что знают, как сказать, религия', 'Спасибо за файлы с графическими изображениями, формат программы Windows', 'Запуск космических челноков НАСА, орбита, лунный, земной', 'Айко Боббин Тек Беаучайн Бронкс Манхэттен Санк Куинс', 'Бог Иисус Библия Атеизм Вера Религия Атеист', 'Объективная моральность Ценности Моральные Субъективные Наука Абсолютные Заявления']

plt.plot(clf.components_[0])

<matplotlib.lines.Line2D at 0x7f0e1039a7b8>

clf.reconstruction_err_

43.71292605795277

NMF: Резюме

Преимущества: быстрый и простой в использовании!

Недостатки: требуется много лет исследований и профессиональных знаний для создания.

Примечание:

  • Для NMF матрица должна быть по крайней мере такой же высокой, как и широкой, иначе мы столкнёмся с ошибкой fit_transform.
  • В CountVectorizer можно использовать df_min для просмотра только k самых распространённых слов в тексте.

Использование SGD для написания NMF с нуля в NumPy

Градиентный спуск

Основная идея градиентного спуска:

  • Случайным образом выбрать некоторые веса для начала.
  • Повторить:
    • Использовать веса для вычисления прогноза.
    • Вычислить производную потерь.
    • Обновить веса.
  • Повторять шаги 2 несколько раз. В итоге мы получаем неплохие веса.

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

Обратите внимание, что потери, ошибки и затраты — это термины, используемые для описания одного и того же.

Давайте посмотрим на заметки курса по градиентному спуску (первоначально из курса глубокого обучения fast.ai).

Стохастический градиентный спуск (SGD)

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

Для стандартного градиентного спуска мы используем все данные для расчёта потерь, что может быть очень медленным. В стохастическом градиентном спуске мы вычисляем нашу функцию потерь только на основе нашей выборки данных (иногда называемой мини-пакетом). Мы получим разные значения потерь на разных выборках данных, поэтому это случайное явление. Оказывается, это всё ещё эффективный способ оптимизации, и он более эффективен!

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

Ресурсы:

Применение SGD к NMF

Цель: Разложить V(mxn) на:

V ≈ WH

где W(mxd) и H(dxn), W, H >= 0, мы минимизируем Frobenius-норму V − WH.

Метод: Мы случайным образом выберем положительные W и H, а затем оптимизируем их с помощью SGD.

Чтобы использовать SGD, нам нужно знать градиент функции потерь.

Источники:

lam=1e3
lr=1e-2
m, n = vectors_tfidf.shape

W1 = clf.fit_transform(vectors)
H1 = clf.components_

show_topics(H1)

['Изображение JPEG, изображение GIF, файл, цветные изображения, качество формата',
'Edu Graphics Pub Mail 128 Ray FTP Send',
'Запуск спутника в космос, спутник НАСА, коммерческий спутник, рынок, год',
'Иисус, Матфей, пророчество, люди, сказал Мессия, Давид, Исайя',
'Данные изображения доступны, обработка программного обеспечения, анализ образования, анализ',
'Атеисты, атеизм, религиозный, верят, люди, религия, делает']

mu = 1e-6 def grads(M, W, H): R = W@H-M return R@H.T + penalty(W, mu)*lam, W.T@R + penalty(H, mu)*lam # dW, dH

def penalty(M, mu): return np.where(M>=mu,0, np.min(M - mu, 0))

def upd(M, W, H, lr): dW,dH = grads(M,W,H) W -= lrdW; H -= lrlr*dH

def report(M,W,H): print(np.linalg.norm(M-W@H), W.min(), H.min(), (W<0).sum(), (H<0).sum())

W = np.abs(np.random.normal(scale=0.01, size=(m,d))) H = np.abs(np.random.normal(scale=0.01, size=(d,n)))

report(vectors_tfidf, W, H)

44.4395133509 5.67503308167e-07 Перевод текста на русский язык:

Этот тренинг очень медленный! Требуется настроить большое количество параметров, но он всё равно очень медленный (или взрывается).

PyTorch

PyTorch — это фреймворк для работы с тензорами и динамическими нейронными сетями на Python с поддержкой GPU. Многие ключевые участники работают в команде AI Facebook. Во многих отношениях он похож на Numpy, но добавляет параллелизацию с использованием GPU.

Как видно из документации PyTorch:

Для дальнейшего изучения: если вы хотите узнать, что такое динамические нейронные сети, вам, возможно, захочется посмотреть выступление Soumith Chintala, исследователя AI Facebook и одного из основных участников PyTorch.

Если вы хотите больше узнать о PyTorch, вы можете попробовать этот учебник или изучить примеры.

Примечание по использованию GPU: если вы не используете GPU, то необходимо удалить .cuda() из следующих методов. Этот курс не требует использования GPU, но я думаю, что некоторые люди будут заинтересованы. Чтобы узнать, как создать экземпляр AWS с помощью GPU, вы можете посмотреть курс конфигурации fast.ai.

import torch
import torch.cuda as tc
from torch.autograd import Variable

def V(M): return Variable(M, requires_grad=True)

v=vectors_tfidf.todense()

t_vectors = 
torch.Tensor(v.astype(np.float32)).cuda()

mu = 1e-5

def grads_t(M, W, H):
    R = W.mm(H)-M
    return (R.mm(H.t()) + penalty_t(W, mu)*lam, 
        W.t().mm(R) + penalty_t(H, mu)*lam) # dW, dH

def penalty_t(M, mu):
    return (M<mu).type(tc.FloatTensor)*torch.clamp(M - mu, max=0.)

def upd_t(M, W, H, lr):
    dW,dH = grads_t(M,W,H)
    W.sub_(lr*dW); H.sub_(lr*dH)

def report_t(M,W,H): 
    print((M-W.mm(H)).norm(2), W.min(), H.min(), (W<0).sum(), (H<0).sum())

t_W = tc.FloatTensor(m,d)
t_H = tc.FloatTensor(d,n)
t_W.normal_(std=0.01).abs_(); 
t_H.normal_(std=0.01).abs_();

d=6; lam=100; lr=0.05

for i in range(1000): 
    upd_t(t_vectors,t_W,t_H,lr)
    if i % 100 == 0: 
        report_t(t_vectors,t_W,t_H)
        lr *= 0.9

'''
44.392791748046875 -0.0060190423391759396 -0.0004986411076970398 1505 2282
43.746803283691406 -0.009054708294570446 -0.011047963984310627 2085 23854
43.702056884765625 -0.008214150555431843 -0.014783496037125587 2295 24432
43.654273986816406 -0.006195350084453821 -0.006913348101079464 2625 22663
43.646759033203125 -0.004638500511646271 -0.003197424579411745 2684 23270
43.645320892333984 -0.005679543130099773 -0.00419645756483078 3242 24199
43.6449089050293 -0.0041352929547429085 -0.00843129213899374 3282 25030
43.64469528198242 -0.003943094052374363 -0.00745873199775815 3129 26220
43.64459991455078 -0.004347225651144981 -0.007400824688374996 3031 26323
43.64434051513672 -0.0039044099394232035 -0.0067480215802788734 3930 33718
'''

show_topics(t_H.cpu().numpy())

'''
['objective morality values moral subjective science absolute claim',
 'god jesus bible believe atheism christian does belief',
 'ico bobbe tek bronx beauchaine manhattan sank queens',
 'thanks graphics files image file program windows know',
 'space nasa launch shuttle orbit lunar moon earth',
 'don people just think like know say religion']
'''

plt.plot(t_H.cpu().numpy()[0])

# [<matplotlib.lines.Line2D at 0x7fe4173f1d68>]
t_W.mm(t_H).max()

0.43389660120010376

t_vectors.max()

0.9188119769096375

PyTorch: автоматический градиент

Выше мы использовали наше знание градиента функции потерь для написания SGD с нуля в PyTorch. Однако у PyTorch есть пакет автоматического градиента, который мы можем использовать. Это очень полезно, потому что мы можем использовать автоматический градиент, когда мы не знаем, что такое производная.

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

В PyTorch переменные и тензоры имеют один и тот же API, но переменные запоминают операции, которые использовались для их создания. Это позволяет нам брать производные.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-fastai-num-linalg-v2-zh.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-fastai-num-linalg-v2-zh.git
oschina-mirror
wizardforcel-fastai-num-linalg-v2-zh
wizardforcel-fastai-num-linalg-v2-zh
master