目录
- Intuition
- 算法流程
- 代码编写
- Reference
Intuition
这个模型是我见过最简单的无监督模型,你听得没错,比Kmeans还简单。但是我为什么还要写这个模型呢?因为这是考试范围里面嘛。。。
回到今天的主题哈,今天我们要解决的问题是,把一个非负矩阵V分解成两个非负矩阵W和H:
为了给出求解的方案,我们首先需要把目标函数写出来
方法一
因为我们的目标函数是二次型的,所以我们求导然后让导数为0,通过迭代的方法优化我们的参数:
方法二
在这篇论文中[2]提出了一种更加有效的优化方法:
没有了,就是这么简单了
算法流程
- 初始化W和H
- 使用方法一或者方法二迭代直到收敛
代码编写
相应的代码在:
https://github.com/JyiHUO/algorithm-from-scratch/tree/master/NMFgithub.comimport numpy as np
from skimage import io
class NMF():
def __init__(self, rank, alpha=0.01, epoch = 20):
self.alpha = alpha
self.epoch = epoch
self.rank = rank
self.W = None
self.H = None
def train(self, X):
# init
row, col = X.shape
v_max, v_min = np.max(X), np.min(X)
W = np.random.rand(row, self.rank) * (v_max - v_min) + v_min
H = np.random.rand(self.rank, col) * (v_max - v_min) + v_min
# update
for e in range(self.epoch):
W = W * ( (X @ H.T)/(W @ H @ H.T) )
H = H * ( (W.T @ X) / (W.T @ W @ H) )
self.W = W
self.H = H
if __name__ == '__main__':
img_src = "https://test87983.oss-cn-shanghai.aliyuncs.com/299536/poster.jpg"
image = io.imread(img_src)
clf = NMF(rank=300, epoch=100)
clf.train(image[:, :, 0])
new_image = clf.W @ clf.H
print(new_image)
print(image[:, :, 0])
new_image = new_image.astype("uint8")
io.imshow(new_image)
io.show()
Reference
- https://zhuanlan.zhihu.com/p/22043930
- http://www.columbia.edu/~jwp2128/Teaching/E4903/papers/nmf_nature.pdf