多变量优化 - scipy.optimize 输入解析错误
Multivariate Optimization - scipy.optimize input parsing error
我将上面的 rgb 图片保存为 tux.jpg
。现在我想得到这个图像的最接近的近似值,它是两个向量的外积,即形式为 A·BT.
这是我的代码 -
#load image to memory
import Image
im = Image.open('tux.jpg','r')
#save image to numpy array
import numpy as np
mat = np.asfarray(im.convert(mode='L')) # mat is a numpy array of dimension 354*300
msizex,msizey = mat.shape
x0 = np.sum(mat,axis=1)/msizex
y0 = np.sum(mat,axis=0)/msizey
X0 = np.concatenate((x0,y0)) # X0.shape is (654,)
# define error of outer product with respect to original image
def sumsquares(X):
""" sum of squares -
calculates the difference between original and outer product
input X is a 1D numpy array with the first 354 elements
representing vector A and the rest 300 representing vector B.
The error is obtained by subtracting the trial $A\cdot B^T$
from the original and then adding the square of all entries in
the matrix.
"""
assert X.shape[0] == msizex+msizey
x = X0[:msizex]
y = X0[msizex:]
return np.sum(
(
np.outer(x,y) - mat
)**2
)
#import minimize
from scipy.optimize import minimize
res = minimize(sumsquares, X0,
method='nelder-mead',
options={'disp':True}
)
xout = res.x[:msizex]
yout = res.x[msizex:]
mout = np.outer(xout,yout)
imout= Image.fromarray(mout,mode='L')
imout.show()
结果是。
Optimization terminated successfully.
Current function value: 158667093349733.531250
Iterations: 19
Function evaluations: 12463
我觉得这不够好。有什么办法可以改善吗?输出中的噪声甚至与原始图片中的结构长度不同。我的猜测是该算法没有通过。我该如何调试或改进它?
EDIT1:我用代码
创建了下面的图像
size = 256
mat0 = np.zeros((size,size))
mat0[size/4:3*size/4,size/4:3*size/4] = 1000
#mat0[size/4:3*size/4,] = 1000
#mat0[:3*size/4,size/4:] = 1000
im0 = Image.fromarray(mat0)
im0.show()
这两行注释掉的结果是另外两张图片。这是我的实验结果 -
- 正方形在中间。
输入 -
输出 - 相同
- 乐队在中间。
输入 -
输出 -
- 东北方的白色大块
输入 -
输出-
虽然这比我预期的要好得多,但案例 2 和案例 3 最终仍然是错误的。我希望 minimize
函数的参数是我认为的意思。
1) 第一张图的渲染问题貌似是numpy数组转图的问题。我通过 运行:
获得了正确的渲染
imout = Image.fromarray(mout/np.max(mout)*255)
(即将图像归一化为最大值255,让它自动判断模式)。
一般来说,要检查 Image.fromarray 是否正常工作,将 imout.show() 的输出与
进行比较很有用
import matplotlib.pyplot as plt
plt.matshow(mout/np.max(mout)*255, cmap=plt.cm.gray)
你应该得到相同的结果。顺便说一句,通过这样做,我得到了所有其他 3 个案例。
2) 其次,tux.png的主要问题是,仅用两个一维向量的外积是不可能重建具有如此详细结构的图像。
(这往往适用于简单的图像,例如上面显示的块状图像,但不适用于具有少量对称性和许多细节的图像)。
为了证明这一点:
存在矩阵分解技术,可以将矩阵重构为两个低秩矩阵 M=AB 的乘积,例如 sklearn.decomposition.NMF。
在这种情况下,将 A 和 B 的等级设置为 1 等同于您的问题(使用不同的优化技术)。
使用下面的代码,您可以很容易地看到 n_components=1(相当于两个一维向量的外积),得到的重构矩阵看起来非常和你的方法输出的差不多,n_components越大重建越好。
为了可重复性:
import matplotlib.pyplot as plt
from sklearn.decomposition import NMF
nmf = NMF(n_components=20)
prj = nmf.fit_transform(mat)
out = prj.dot(nmf.components_)
out = np.asarray(out, dtype=float)
imout = Image.fromarray(out)
imout.show()
为了说明,这是具有 1 个分量的 NMF 重建(这恰好是两个一维向量之间的外积):
有 2 个组件:
这是具有 20 个分量的 NMF 重建。
这清楚地表明单个一维外积对于此图像是不够的。但是它适用于块状图像。
如果您不局限于向量的外积,则可以选择矩阵分解。顺便说一句,存在大量的矩阵分解技术。 sklearn 中的另一种选择是 SVD。
3) 最后,x0 和 y0 可能存在缩放问题。请注意,np.outer(x0, y0) 的元素比 mat 的元素高几个数量级。
虽然我仍然使用提供的代码在 3 个块状示例中获得了不错的结果,但一般来说,在计算平方差时具有可比较的比例是一个很好的做法。例如,您可能希望缩放 x0 和 y0,以便 np.outer 的范数与 mat 的范数相当。
我将上面的 rgb 图片保存为 tux.jpg
。现在我想得到这个图像的最接近的近似值,它是两个向量的外积,即形式为 A·BT.
这是我的代码 -
#load image to memory
import Image
im = Image.open('tux.jpg','r')
#save image to numpy array
import numpy as np
mat = np.asfarray(im.convert(mode='L')) # mat is a numpy array of dimension 354*300
msizex,msizey = mat.shape
x0 = np.sum(mat,axis=1)/msizex
y0 = np.sum(mat,axis=0)/msizey
X0 = np.concatenate((x0,y0)) # X0.shape is (654,)
# define error of outer product with respect to original image
def sumsquares(X):
""" sum of squares -
calculates the difference between original and outer product
input X is a 1D numpy array with the first 354 elements
representing vector A and the rest 300 representing vector B.
The error is obtained by subtracting the trial $A\cdot B^T$
from the original and then adding the square of all entries in
the matrix.
"""
assert X.shape[0] == msizex+msizey
x = X0[:msizex]
y = X0[msizex:]
return np.sum(
(
np.outer(x,y) - mat
)**2
)
#import minimize
from scipy.optimize import minimize
res = minimize(sumsquares, X0,
method='nelder-mead',
options={'disp':True}
)
xout = res.x[:msizex]
yout = res.x[msizex:]
mout = np.outer(xout,yout)
imout= Image.fromarray(mout,mode='L')
imout.show()
结果是
Optimization terminated successfully.
Current function value: 158667093349733.531250
Iterations: 19
Function evaluations: 12463
我觉得这不够好。有什么办法可以改善吗?输出中的噪声甚至与原始图片中的结构长度不同。我的猜测是该算法没有通过。我该如何调试或改进它?
EDIT1:我用代码
创建了下面的图像size = 256
mat0 = np.zeros((size,size))
mat0[size/4:3*size/4,size/4:3*size/4] = 1000
#mat0[size/4:3*size/4,] = 1000
#mat0[:3*size/4,size/4:] = 1000
im0 = Image.fromarray(mat0)
im0.show()
这两行注释掉的结果是另外两张图片。这是我的实验结果 -
- 正方形在中间。
输入 -
输出 - 相同 - 乐队在中间。
输入 -
输出 - - 东北方的白色大块
输入 -
输出-
虽然这比我预期的要好得多,但案例 2 和案例 3 最终仍然是错误的。我希望 minimize
函数的参数是我认为的意思。
1) 第一张图的渲染问题貌似是numpy数组转图的问题。我通过 运行:
获得了正确的渲染imout = Image.fromarray(mout/np.max(mout)*255)
(即将图像归一化为最大值255,让它自动判断模式)。
一般来说,要检查 Image.fromarray 是否正常工作,将 imout.show() 的输出与
进行比较很有用import matplotlib.pyplot as plt
plt.matshow(mout/np.max(mout)*255, cmap=plt.cm.gray)
你应该得到相同的结果。顺便说一句,通过这样做,我得到了所有其他 3 个案例。
2) 其次,tux.png的主要问题是,仅用两个一维向量的外积是不可能重建具有如此详细结构的图像。
(这往往适用于简单的图像,例如上面显示的块状图像,但不适用于具有少量对称性和许多细节的图像)。
为了证明这一点:
存在矩阵分解技术,可以将矩阵重构为两个低秩矩阵 M=AB 的乘积,例如 sklearn.decomposition.NMF。
在这种情况下,将 A 和 B 的等级设置为 1 等同于您的问题(使用不同的优化技术)。
使用下面的代码,您可以很容易地看到 n_components=1(相当于两个一维向量的外积),得到的重构矩阵看起来非常和你的方法输出的差不多,n_components越大重建越好。
为了可重复性:
import matplotlib.pyplot as plt
from sklearn.decomposition import NMF
nmf = NMF(n_components=20)
prj = nmf.fit_transform(mat)
out = prj.dot(nmf.components_)
out = np.asarray(out, dtype=float)
imout = Image.fromarray(out)
imout.show()
为了说明,这是具有 1 个分量的 NMF 重建(这恰好是两个一维向量之间的外积):
有 2 个组件:
这是具有 20 个分量的 NMF 重建。
这清楚地表明单个一维外积对于此图像是不够的。但是它适用于块状图像。
如果您不局限于向量的外积,则可以选择矩阵分解。顺便说一句,存在大量的矩阵分解技术。 sklearn 中的另一种选择是 SVD。
3) 最后,x0 和 y0 可能存在缩放问题。请注意,np.outer(x0, y0) 的元素比 mat 的元素高几个数量级。
虽然我仍然使用提供的代码在 3 个块状示例中获得了不错的结果,但一般来说,在计算平方差时具有可比较的比例是一个很好的做法。例如,您可能希望缩放 x0 和 y0,以便 np.outer 的范数与 mat 的范数相当。