首页 > 人工智能 > 深度学习 > 使用神经网络生成抽象随机艺术
https://www.toutiao.com/a6657911844235117059/
随着深度神经网络作为分类或回归模型变得非常流行,这些模型也可以用作生成模型来创建人工数据,例如创建新图像甚至文本数据。
下面是使用抽象艺术生成算法完成的生成的图像:
生成的RGB图像(512x512)
这个实现是在python NumPy中实现的,并解释了图像生成的工作方式。
随机训练神经网络时,初始化权重矩阵“W i ,i=1,....,n l +1”,其中n l 为神经网络的隐藏层数。
在这个实现中,权重将通过绘制标准正态分布 N(μ=0,σ2=1) 来初始化,如下面的代码所示:
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
import argparse
import sys
import os
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import time
### Draw a large vector of random numbers by standard normal distribution
random_numbers = np.random.normal(loc=0.0, scale=1.0, size=2000)
### Now suppose we wanted to approximate the density function of those random numbers, we suppose
### the kernel density estimate to look like the standard normal distribution
sns.set_style("whitegrid")
sns.kdeplot(random_numbers, bw=0.5)
<matplotlib.axes._subplots.AxesSubplot at 0x9a66550>
随机艺术算法是如何工作的
神经网络主要用作分类或回归模型。
假设我们有一些输入数据X i ,想要预测结果Y i ,其中X i 是维度p的向量,Y i 是维度k的向量。
在这种情况下,我们有一个预测可能的类k的分类问题。
对于生成的艺术,取决于我们想要选择的颜色模式(RGB、灰度、CMYK和HSL(HSV)),在输出层中我们有3个、1个、4个或3个输出神经元。
由于(对于float数据类型)这些 “ colour-values ”(颜色值) 的范围是[0,1],因此每个输出神经元的 “ weighted_input ”(加权输入) 将被转换为一个sigmoid激活函数,如下所示:
x = np.arange(-10, 10, 0.1)
sigmoid = 1 / (1 + np.exp(-x))
plt.plot(x, sigmoid)
plt.xlabel("weighted_input")
plt.ylabel("color-value")
plt.show()
对于隐藏层激活,可以选择不同的激活函数,但是由于我们通过sigmoid映射weighted_input并希望colour-values大约在0.25-0.75范围之间创建。因此对于每个隐藏层,tanh激活将如下所示。注意,这个实现在默认情况下选择默认激活函数。在后面我写了一个NeuralNet类,它可以通过输入参数列表layers_dims和activations_fnc来选择不同的隐藏层神经元和层激活(但对于输出层,请确保激活函数映射到范围[0,1])。
x = np.arange(-10, 10, 0.1)
tanh = np.tanh(x)
plt.plot(x, tanh)
plt.xlabel("x")
plt.ylabel("tanh(x)")
plt.show()
该算法还组合了alpha通道,alpha通道是一个8位的灰度通道,该通道记录图像中的透明度信息,定义为透明、不透明和半透明 。当一种颜色(源图)与另一种颜色(背景图)混合时,例如,当一幅图像被叠加到另一幅图像上时,源图颜色的alpha值用于确定最终的颜色。如果alpha值不透明,源图颜色将覆盖目标颜色;如果是透明的,源图颜色是不可见的,显示背景图颜色。如果alpha值介于两者之间,则生成的颜色具有不同程度的前后背景混合颜色,从而创建半透明效果。
输出层中的颜色值将通过计算输入数据的前向传递来生成。因此,很容易实现一个NeuralNet类及其所需的方法,在这种情况下:
class NeuralNet:
def __init__(self, layers_dims, activations_fnc, type_="classif"):
self.type_ = type_
self.W = [None] * (len(layers_dims)-1)
self.b = [None] * (len(layers_dims)-1)
self.out = [None] * (len(layers_dims)-1)
self.layers_dims = layers_dims
self.activations_fnc = activations_fnc
for i in range(len(layers_dims)-1):
self.b[i] = np.random.randn(layers_dims[i+1]).reshape(1, layers_dims[i+1])
self.W[i] = np.random.randn(layers_dims[i], layers_dims[i+1])
def sigmoid(self, x):
return 1.0 / (1.0 + np.exp(-x))
def tanh(self, x):
return np.tanh(x)
def relu(self, x):
return np.maximum(x, 0)
def identity(self, x):
return x
def softsign(self,x):
return x / (1 + np.abs(x))
def sin(self, x):
return np.sin(x)
def cos(self, x):
return np.cos(x)
def softmax(self, x):
exp_scores = np.exp(x)
out = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
return out
def activation(self, x, t):
t = t.lower()
if t == "sigmoid":
return self.sigmoid(x)
elif t == "tanh":
return self.tanh(x)
elif t == "relu":
return self.relu(x)
elif t == "identity":
return self.identity(x)
elif t == "softsign":
return self.softsign(x)
elif t == "sin":
return self.sin(x)
elif t == "cos":
return self.cos(x)
elif t == "softmax":
return self.softmax(x)
else:
raise Exception("Non-supported activation function {}".format(t))
def multiply(self, x, W):
m = np.dot(x, W)
return m
def add(self, m, b):
return m + b
def forward(self, x):
input_ = x
for i, activation in enumerate(self.activations_fnc) :
weighted_sum = self.multiply(x=input_, W=self.W[i])
weighted_sum = self.add(m=weighted_sum, b=self.b[i])
input_ = self.out[i] = self.activation(x=weighted_sum, t=activation)
注意,权重初始化是用np.random.randn()函数和定义类方法forward()完成的计算从上一层到下一层的正向传播。仅实现这些类方法就足够了。这个类不包括反向传播和训练神经网络分类/回归模型所需的任何东西,因为这里的目的在于理解艺术生成过程。
为随机艺术生成输入参数
由于用户必须定义生成的图像的大小,因此image_height和image_width是必需的。
此外,必须定义使用哪种颜色模式以及是否应该使用alpha通道。
对于输出图像,将使用numpy.ndarray来表示图像。图像的形状将是( img_height, img_width, 4 )。如果您熟悉图像处理或卷积神经网络,通常会看到形状( img_height, img_width, 3 )。如果我们有一个灰度图像,图像实际上是一个2D-tensor。对于灰度图像,我们只需将初始灰度的每个值复制到RGB图像第三轴的每个维数中,即可得到RGB形状,例如通过np.resize:
到目前为止还没有问题。但是我们生成的图像在三维中有4个通道。这来自于alpha通道的建模。默认情况下,我们只创建这个定义的图像形状,但如果我们不想包含图像中每个像素的alpha-channel-random-modelling,输出的alpha值将是1(意思是完全不透明度)。RGBA变成了RGB。
对于“CMYK”、“HSV”、“HSL”(输出范围均为[0,1])的颜色模式,这些值将转换为RGB格式,因为对于图像显示和保存,我们假设是RGB图像,python实现如下。
def init_image(rows, cols):
img = np.zeros(shape=(rows, cols, 4))
return img
def hsv_to_rgb(h, s, v):
## hsw are between 0 and 1
## returns rgb between 0 and 1
## from: https://bgrins.github.io/TinyColor/docs/tinycolor.html
h *= 6
i = np.floor(h)
f = h-i
p = v*(1-s)
q = v*(1-f*s)
t = v*(1-(1-f)*s)
mod = int(i % 6)
r = [v, q, p, p, t, v][mod]
g = [t, v, v, q, p, p][mod]
b = [p, p, t, v, v, q][mod]
return r,g,b
def hsl_to_rgb(h, s, l):
## hsl are between 0 and 1
## returns rgb between 0 and 1
def hue_to_rgb(p, q, t):
if t < 0:
t += 1
if t > 1:
t -= 1
if t < 1/6:
return p+(q-p)*6*t
if t < 1/2:
return q
if t < 2/3:
return p+(q-p)*(2/3-t)*6
if s==0:
r = g = b = l #achromatic
else:
if l < 0.5:
q = l*(1+s)
else:
q = l+s-l*s
p = 2*l-q
r = hue_to_rgb(p, q, h + 1/3)
g = hue_to_rgb(p, q, h)
b = hue_to_rgb(p, q, h - 1/3)
return r,g,b
神经网络架构
网络参数和输入
对于神经网络,我们需要定义输入维度、层数和激活函数。
作为输入,我们有一个5维向量。假设我们有一个大小为(256,256)的图像,把它看作一个二维矩阵。该算法对每个像素p_{i,j}计算r,g,b,a的值。
因此,在为生成的图像中的每个像素生成r、g、b、a值作为输入时(计算2-nested循环)我们取:
其中“factor=min(img height ,img width )”从而得到“input i,j =(x,y,r,z 1 ,z 2 )”。
将嵌套for循环中的x,y,r的值进行映射,从而创建结果图像中输入数据的相互依赖和相关性:
注意,通过嵌套循环,x和y将是相互依赖的,如果生成的图像是正方形( img_height=img_width ),则输入数据组件x和y始终小于1。
现在为生成艺术做layers和activation_fnc列表做准备工作。
注意,这也可以写成硬编码,而不是通过prep_nnet_arch函数定义:
def prep_nnet_arch(n_depth, n_size, activation, colormode, alpha):
layers = [5] #x, y, r, z1, z2
for i in range(n_depth):
layers.append(n_size)
colormode = colormode.lower()
### Output layer. Append number of output neurons depending on which colormode is selected
if colormode in ["rgb", "hsv", "hsl"] : #RGB
if not alpha:
layers.append(3)
else:
layers.append(4)
elif colormode == "cmyk":
if not alpha:
layers.append(4)
else:
layers.append(5)
elif colormode == "bw":
if not alpha:
layers.append(1)
else:
layers.append(2)
else:
print("Inserted colormode '{}' is not part ob supported ones: [rgb, bw, cmyk, hsv, hsl]".format(colormode))
raise Exception("Non-supported colormode {}".format(colormode))
possibles = ["sigmoid", "tanh", "relu", "identity", "softsign", "sin", "cos", "softmax"]
if not activation.lower() in possibles:
print('defined activation {} not supported in {}'.format(activation, str(possibles)))
return None
activations_fnc = [activation] * (len(layers)-2)
activations_fnc.append("sigmoid")
return layers, activations_fnc
如果执行以下代码 :
n_depth = 4
n_size = 10
activation = "tanh"
colormode = "rgb"
alpha = True
layers, activations_fnc = prep_nnet_arch(n_depth, n_size, activation, colormode, alpha)
print("layers: {}".format(str(layers)))
print("activations: {}".format(str(activations_fnc)))
将生成以下神经网络:
用R,G,B,A的值填充图像
def get_color_at(nnet, x, y, r, z1, z2, colormode, alpha):
input_ = np.array([x, y, r, z1, z2], dtype=np.float32).reshape(1, 5)
nnet.forward(input_)
colormode = colormode.lower()
if colormode == "rgb": ## Output via sigmoid activation mapped into range [0,1]
r = nnet.out[len(nnet.out)-1][0][0]
g = nnet.out[len(nnet.out)-1][0][1]
b = nnet.out[len(nnet.out)-1][0][2]
a_index = 3
elif colormode == "bw":
r=g=b = nnet.out[len(nnet.out)-1][0][0]
a_index = 1
elif colormode == "cmyk":
c = nnet.out[len(nnet.out)-1][0][0]
m = nnet.out[len(nnet.out)-1][0][1]
y = nnet.out[len(nnet.out)-1][0][2]
k = nnet.out[len(nnet.out)-1][0][3]
r = (1-c)*k
g = (1-m)*k
b = (1-y)*k
a_index = 4
elif colormode == "hsv":
h = nnet.out[len(nnet.out)-1][0][0]
s = nnet.out[len(nnet.out)-1][0][1]
v = nnet.out[len(nnet.out)-1][0][2]
r, g, b = hsv_to_rgb(h, s, v)
a_index = 3
elif colormode == "hsl":
h = nnet.out[len(nnet.out)-1][0][0]
s = nnet.out[len(nnet.out)-1][0][1]
l = nnet.out[len(nnet.out)-1][0][2]
r, g, b = hsl_to_rgb(h, s, l)
a_index = 3
else:
print("Inserted colormode '{}' is not part ob supported ones: [rgb, bw, cmyk, hsv, hsl]".format(colormode))
raise Exception("Non-supported colormode {}".format(colormode))
if alpha:
# Since non blackmode [rgb, cmyk, hsv, hsl] values are mapped onto [0,1] the alpha channel is also between [0,1].
#0=transparency, 1=opaque wrt. to overlaying
a = 1-abs(2*nnet.out[len(nnet.out)-1][0][a_index]-1)
a = 0.25 + 0.75*a
else:
a = 1.0
return r, g, b, a
生成图像函数
函数的要点:
1、初始化输出图像
2、初始化网络参数(层和激活)
3、从图像中遍历行和列以填充r、g、b、a的值
def generate_image(img_height, img_width, n_depth, n_size, activation, colormode, alpha, z1, z2,
fname="netart.png", nnet_dict=None, save=False, show=False):
factor = min(img_height, img_width)
if nnet_dict is None:
layers, activations_fnc = prep_nnet_arch(n_depth, n_size, activation, colormode, alpha)
else:
try:
layers = nnet_dict["layers"]
activations_fnc = nnet_dict["activations_fnc"]
assert len(activations_fnc) == len(layers)-1
assert layers[0] == 5
assert activations_fnc[-1].lower() in ["sigmoid", "softmax"]
except Exception as e:
print(e)
nnet = NeuralNet(layers, activations_fnc)
img = init_image(img_height, img_width)
for i in range(img_height):
for j in range(img_width):
x = i/factor - 0.5
y = j/factor - 0.5
r_ = np.sqrt(x*x + y*y)
#Get RGBA values
r, g, b, a = get_color_at(nnet, x=x, y=y, r=r_,
z1=z1, z2=z2, colormode=colormode, alpha=alpha)
#Populate the image
img[i, j, 0] = r
img[i, j, 1] = g
img[i, j, 2] = b
img[i, j, 3] = a
if not show:
matplotlib.use("Agg")
plt.figure()
fig = plt.imshow(img, interpolation="bilinear", aspect="auto")
plt.axis("off")
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
if show:
plt.show()
if save:
plt.imsave("{}".format(fname), img, format="png")
return img
使用随机设置运行算法:
## This is fix
img_height = img_width = 256
activation = "tanh"
def randomize_configs():
n_size = int(np.random.randint(low=12, high=20, size=1))
n_depth = int(24 - n_size)
colormode = np.random.choice(a=["rgb", "bw", "cmyk", "hsl", "hsv"], size=1)[0]
alpha = bool(np.random.choice(a=[True, False], size=1))
z1 = float(np.round(np.random.uniform(low=-1.0, high=1.0, size=1), decimals=5))
z2 = float(np.round(np.random.uniform(low=-1.0, high=1.0, size=1), decimals=5))
return n_size, n_depth, colormode, alpha, z1, z2
n_images = 10
if not os.path.exists("nb_output"):
os.makedirs("nb_output")
使用随机配置运行算法10次,并将结果保存在nb_output子目录中:
for i in range(n_images):
n_size, n_depth, colormode, alpha, z1, z2 = randomize_configs()
print("Settings:")
print("n_size: {}".format(n_size))
print("n_depth: {}".format(n_depth))
print("colormode: {}".format(colormode))
print("alpha: {}".format(alpha))
print("z1: {}".format(z1))
print("z2: {}".format(z2))
print("--------")
fname = "nb_output/generated_{}_{}.png".format(colormode, i+1)
print("Generated image: {}".format(i+1))
start_time = time.time()
generate_image(img_height, img_width, n_depth, n_size, activation, colormode, alpha, z1, z2,
show=True, nnet_dict=None, fname=fname, save=True)
delta = time.time() - start_time
print("Generating image {} took {} seconds".format(i+1, delta))
设置:
n_size: 13
n_depth: 11
colormode: hsv
alpha: True
z1: -0.84136
z2: 0.97109
--------
生成图像: 1
生成图像1耗时4.51595664024353秒
设置:
n_size: 13
n_depth: 11
colormode: rgb
alpha: True
z1: -0.72624
z2: -0.19368
--------
生成图像: 2
生成图像2耗时4.032962322235107秒
设置:
n_size: 14
n_depth: 10
colormode: bw
alpha: False
z1: 0.14255
z2: -0.38622
--------
生成图像: 3
生成图像3耗时3.508967638015747秒
设置:
n_size: 12
n_depth: 12
colormode: rgb
alpha: True
z1: -0.39475
z2: -0.67197
--------
生成图像: 4
生成图像4耗时4.089961051940918秒
设置:
n_size: 12
n_depth: 12
colormode: hsl
alpha: True
z1: 0.95898
z2: -0.00935
--------
生成图像: 5
生成图像5耗时4.7219579219818115秒
设置:
n_size: 18
n_depth: 6
colormode: bw
alpha: False
z1: 0.30633
z2: 0.09442
--------
生成图像: 6
生成图像6耗时2.670975923538208秒
设置:
n_size: 19
n_depth: 5
colormode: bw
alpha: True
z1: 0.91837
z2: -0.34998
--------
生成图像: 7
生成图像7耗时2.580977201461792秒
设置:
n_size: 15
n_depth: 9
colormode: hsl
alpha: True
z1: -0.385
z2: 0.92596
--------
生成图像: 8
生成图像8耗时4.372961521148682秒
设置:
n_size: 18
n_depth: 6
colormode: bw
alpha: False
z1: 0.72774
z2: -0.89946
--------
生成图像: 9
生成图像9耗时2.6779751777648926秒
设置:
n_size: 15
n_depth: 9
colormode: cmyk
alpha: True
z1: 0.14114
z2: 0.49769
--------
生成图像: 10
生成图像10耗时3.770965099334717秒
生成具有定义的网络参数的图像
如上所述,可以通过层列表来定义隐藏层尺寸和隐藏层内的神经元。
确保层列表的第一个元素是5(因为有5个输入值)。因此层[0]= 5。
在CMYK颜色模式的情况下,输出神经元的大小应该是4。因此层[-1]= 4。
对于RGB、B&W、HSV、HSL等颜色模式,输出神经元均为3。因此层[-1]= 3。
如果alpha通道也被使用,输出层需要被1填充。因此层[-1] +=1。
img_height = img_width = 512
colormode = "cmyk"
alpha = False
activations_fnc = ["tanh", "softsign", "identity", "tanh", "sigmoid"]
layers = [5, 10, 8, 18, 13, 4]
if alpha:
layers[-1] += 1
nnet_dict = {"layers":layers, "activations_fnc":activations_fnc}
z1 = -0.99
z2 = 0.85
start_time = time.time()
generate_image(img_height=img_height, img_width=img_width,
n_depth=None, n_size=None, activation=None,
colormode=colormode, alpha=alpha, z1=z1, z2=z2,
nnet_dict=nnet_dict,
show=True, save=False)
delta = time.time() - start_time
print("Generating image took {} seconds".format(delta))
生成图像耗时9.125910997390747秒
img_height = img_width = 512
colormode = "hsv"
alpha = True
activations_fnc = ["tanh", "softsign", "relu", "tanh", "sigmoid"]
layers = [5, 10, 20, 18, 25, 3]
if alpha:
layers[-1] += 1
nnet_dict = {"layers":layers, "activations_fnc":activations_fnc}
z1 = -0.45
z2 = 0.66
start_time = time.time()
generate_image(img_height=img_height, img_width=img_width,
n_depth=None, n_size=None, activation=None,
colormode=colormode, alpha=alpha, z1=z1, z2=z2,
nnet_dict=nnet_dict,
show=True, save=False)
delta = time.time() - start_time
print("Generating image took {} seconds".format(delta))
生成图像耗时11.697889804840088秒
img_height = img_width = 512
colormode = "bw"
alpha = False
activations_fnc = ["tanh", "softsign", "softsign", "tanh", "sigmoid"]
layers = [5, 10, 30, 40, 50, 3]
if alpha:
layers[-1] += 1
nnet_dict = {"layers":layers, "activations_fnc":activations_fnc}
z1 = 0.255
z2 = 0.900
start_time = time.time()
generate_image(img_height=img_height, img_width=img_width,
n_depth=None, n_size=None, activation=None,
colormode=colormode, alpha=alpha, z1=z1, z2=z2,
nnet_dict=nnet_dict,
show=True, save=False)
delta = time.time() - start_time
print("Generating image took {} seconds".format(delta))
生成图像耗时9.826904296875秒
img_height = img_width = 512
colormode = "hsl"
alpha = False
activations_fnc = ["tanh", "sin", "cos", "tanh", "sigmoid"]
layers = [5, 20, 10, 30, 40, 3]
if alpha:
layers[-1] += 1
nnet_dict = {"layers":layers, "activations_fnc":activations_fnc}
z1 = 0.255
z2 = 0.900
start_time = time.time()
generate_image(img_height=img_height, img_width=img_width,
n_depth=None, n_size=None, activation=None,
colormode=colormode, alpha=alpha, z1=z1, z2=z2,
nnet_dict=nnet_dict,
show=True, save=False)
delta = time.time() - start_time
print("Generating image took {} seconds".format(delta))
生成图像耗时9.72290325164795秒
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29829936/viewspace-2636099/ ,如需转载,请注明出处,否则将追究法律责任。