写在篇前
本篇文章主要介绍NMF算法原理以及使用sklearn中的封装方法实现该算法,最重要的是理解要NMF矩阵分解的实际意义,将其运用到自己的数据分析中!
理论概述
NMF(Non-negative matrix factorization),即对于任意给定的一个非负矩阵V,其能够寻找到一个非负矩阵W和一个非负矩阵H,满足条件V=W*H,从而将一个非负的矩阵分解为左右两个非负矩阵的乘积。**其中,V矩阵中每一列代表一个观测(observation),每一行代表一个特征(feature);W矩阵称为基矩阵,H矩阵称为系数矩阵或权重矩阵。这时用系数矩阵H代替原始矩阵,就可以实现对原始矩阵进行降维,得到数据特征的降维矩阵,从而减少存储空间。**过程如下图所示:
在这里插入图片描述
nmf更详尽的原理可以参考Non-negative matrix factorization – Wikipedia,这里我主要列出我很关注的损失函数(lossFunction or objective function):
- squared frobenius norm a r g m i n ⎵ W , H 1 2 ∣ ∣ A − W H ∣ ∣ F r o 2 + α ρ ∣ ∣ W ∣ ∣ 1 + α ρ ∣ ∣ H ∣ ∣ 1 + α ( 1 − ρ ) 2 ∣ ∣ W ∣ ∣ F r o 2 + α ( 1 − ρ ) 2 ∣ ∣ H ∣ ∣ F r o 2 \underbrace{arg;min}{W,H}\frac{1}{2}||A-WH||{Fro}^2 +\alpha\rho|| W||1+\alpha\rho|| H||1+\frac{\alpha(1-\rho)}{2}|| W||{Fro}^2 + \frac{\alpha(1-\rho)}{2}|| H||{Fro}^2 W,H argmin21∣∣A−WH∣∣Fro2+αρ∣∣W∣∣1+αρ∣∣H∣∣1+2α(1−ρ)∣∣W∣∣Fro2+2α(1−ρ)∣∣H∣∣Fro2 其中: 1 2 ∣ ∣ A − W H ∣ ∣ F r o 2 = 1 2 ∑ i , j ( A i j − W H i j ) 2 \frac{1}{2} ||A – WH||{\mathrm{Fro}}^2 = \frac{1}{2} \sum{i,j} (A_{ij} – {WH}_{ij})^2 21∣∣A−WH∣∣Fro2=21i,j∑(Aij−WHij)2 α \alpha α为L1&L2正则化参数,而\rho为L1正则化占总正则化项的比例。||*||_1为L1范数。
- Kullback-Leibler (KL) d K L ( X , Y ) = ∑ i , j ( X i j log ( X i j Y i j ) − X i j + Y i j ) d_{KL}(X, Y) = \sum_{i,j} (X_{ij} \log(\frac{X_{ij}}{Y_{ij}}) – X_{ij} + Y_{ij}) dKL(X,Y)=i,j∑(Xijlog(YijXij)−Xij+Yij)
- Itakura-Saito (IS)
d I S ( X , Y ) = ∑ i , j ( X i j Y i j − log ( X i j Y i j ) − 1 ) d_{IS}(X, Y) = \sum_{i,j} (\frac{X_{ij}}{Y_{ij}} – \log(\frac{X_{ij}}{Y_{ij}}) – 1) dIS(X,Y)=i,j∑(YijXij−log(YijXij)−1) 实际上,上面三个公式是beta-divergence family中的三个特殊情况(分别是当 β = 2 , 1 , 0 \beta = 2, 1, 0 β=2,1,0),其原型是: d β ( X , Y ) = ∑ i , j 1 β ( β − 1 ) ( X i j β + ( β − 1 ) Y i j β − β X i j Y i j β − 1 ) d_{\beta}(X, Y) = \sum_{i,j} \frac{1}{\beta(\beta – 1)}(X_{ij}^\beta + (\beta-1)Y_{ij}^\beta – \beta X_{ij} Y_{ij}^{\beta – 1}) dβ(X,Y)=i,j∑β(β−1)1(Xijβ+(β−1)Yijβ−βXijYijβ−1)
代码实现
代码解读
在sklearn封装了NMF的实现,可以非常方便我们的使用,其实现基本和前面理论部分的实现是一致的,但是注意sklearn中输入数据的格式是(samples, features):
from sklearn.decomposition import NMF
from sklearn.datasets import load_iris
X, _ = load_iris(True)
# can be used for example for dimensionality reduction, source separation or topic extraction
# 个人认为最重要的参数是n_components、alpha、l1_ratio、solver
nmf = NMF(n_components=2, # k value,默认会保留全部特征
init=None, # W H 的初始化方法,包括'random' | 'nndsvd'(默认) | 'nndsvda' | 'nndsvdar' | 'custom'.
solver='cd', # 'cd' | 'mu'
beta_loss='frobenius', # {'frobenius', 'kullback-leibler', 'itakura-saito'},一般默认就好
tol=1e-4, # 停止迭代的极限条件
max_iter=200, # 最大迭代次数
random_state=None,
alpha=0., # 正则化参数
l1_ratio=0., # 正则化参数
verbose=0, # 冗长模式
shuffle=False # 针对"cd solver"
)
# -----------------函数------------------------
print('params:', nmf.get_params()) # 获取构造函数参数的值,也可以nmf.attr得到,所以下面我会省略这些属性
# 下面四个函数很简单,也最核心,例子中见
nmf.fit(X)
W = nmf.fit_transform(X)
W = nmf.transform(X)
nmf.inverse_transform(W)
# -----------------属性------------------------
H = nmf.components_ # H矩阵
print('reconstruction_err_', nmf.reconstruction_err_) # 损失函数值
print('n_iter_', nmf.n_iter_) # 实际迭代次数
注意点:
init
参数中,nndsvd(默认)
更适用于sparse factorization,其变体则适用于dense factorization.solver
参数中,如果初始化中产生很多零值,Multiplicative Update (mu
) 不能很好更新。所以mu
一般不和nndsvd
使用,而和其变体nndsvda
、nndsvdar
使用。solver
参数中,cd
只能优化Frobenius norm函数;而mu
可以更新所有损失函数
案例1
第一个案例很简单,目的是理解分解出来的这两个矩阵能用来干嘛,分别是什么意思,但是其实我在文章第一部分已经解释了,直接看例子:
>>> import numpy as np
>>> X = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]])
>>> from sklearn.decomposition import NMF
>>> model = NMF(n_components=2, init='random', random_state=0)
>>> W = model.fit_transform(X)
>>> H = model.components_
>>> X_new = np.array([[1, 0], [1, 6.1], [1, 0], [1, 4], [3.2, 1], [0, 4]])
>>> W_new = model.transform(X_new)
>>> W_new # 输出 W_new
array([[0.35919303], [0.86264547], [0.35919303], [0.68932578], [1.23195088], [0.33013275]])
ok,这个小例子就说明了我们通过NMF获得系数矩阵H
,并用系数矩阵H
获得新矩阵W_new
的基矩阵,实现W_new
的数据降维(or 特征提取)。实际上,这时W_new = model.transform(X_new)
做的工作相当于:
np.mat(X_new)*(np.mat(H).I)
matrix([[0.35919303], [0.86264547], [0.35919303], [0.68932578], [1.23195088], [0.33013275]])
案例2
这里再举一个NMF在图像特征提取的应用,来自官方示例,根据我的需要改动了一些:
from time import time
from numpy.random import RandomState
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_olivetti_faces
from sklearn import decomposition
n_row, n_col = 2, 3
n_components = n_row * n_col
image_shape = (64, 64)
rng = RandomState(0)
# #############################################################################
# Load faces data
dataset = fetch_olivetti_faces('./', True,
random_state=rng)
faces = dataset.data
n_samples, n_features = faces.shape
print("Dataset consists of %d faces, features is %s" % (n_samples, n_features))
def plot_gallery(title, images, n_col=n_col, n_row=n_row, cmap=plt.cm.gray):
plt.figure(figsize=(2. * n_col, 2.26 * n_row))
plt.suptitle(title, size=16)
for i, comp in enumerate(images):
plt.subplot(n_row, n_col, i + 1)
vmax = max(comp.max(), -comp.min())
plt.imshow(comp.reshape(image_shape), cmap=cmap,
interpolation='nearest',
vmin=-vmax, vmax=vmax)
plt.xticks(())
plt.yticks(())
plt.subplots_adjust(0.01, 0.05, 0.99, 0.93, 0.04, 0.)
# #############################################################################
estimators = [
('Non-negative components - NMF',
decomposition.NMF(n_components=n_components, init='nndsvda', tol=5e-3))
]
# #############################################################################
# Plot a sample of the input data
plot_gallery("First centered Olivetti faces", faces[:n_components])
# #############################################################################
# Do the estimation and plot it
for name, estimator in estimators:
print("Extracting the top %d %s..." % (n_components, name))
t0 = time()
data = faces
estimator.fit(data)
train_time = (time() - t0)
print("done in %0.3fs" % train_time)
components_ = estimator.components_
print('components_:', components_.shape, '\n**\n', components_)
plot_gallery('%s - Train time %.1fs' % (name, train_time),
components_)
plt.show()
#---------------------------其他注释---------------------------
V矩阵:400*4096
W矩阵:400*6
H矩阵:6*4096
下面是script运行结果:
在这里插入图片描述
写在篇后
NMF最早由科学家D.D.Lee和H.S.Seung提出的一种非负矩阵分解方法,并在Nature发表文章《Learning the parts of objects by non-negative matrix factorization》。随后也有了很多NMF变体,应用也越发广泛,包括文本降维、话题提取、图像处理等。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费
】
😝有需要的小伙伴,可以Vx扫描下方二维码免费领取==🆓