TensorFlow2框架使用---模型搭建

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: TensorFlow2框架使用---模型搭建

TF的模型搭建


总的来说常见带监督的机器学习问题分为两类:分类回归,我们使用Tensorflow来解决这些问题的时候就得自己搭建网络模型,但是对于TensorFlow不同级别的API也就产生了不同的模型搭建方式。越底层的API灵活性越大,可以更加自由地添加自己想加入的内容,但是编码难度就有所提高;反之,越高阶的api具有更好的封装性,简单的几行代码就能实现模型的搭建,但是灵活性难以避免的有所下降。今天就讲讲几种不同层次API搭建网络的方式。


1.回归问题


1.1 数据生成


首先我们得自己设计一个回归问题,也就是建一个方程,然后训练网络去拟合它。

我们熟知的线性方程:Y=W∗X+bY=W*X+bY=WX+b


我们这里生成200个数据,X是在(-10,10)之间的均匀分布,W为(2,-2),b=3,另外添加噪音


# 设置随机数种子
tf.random.set_seed(0)
# 样本数
n=200
# 生成测试用数据集
# Y=WX+b+noise
# 相当于两个方程: Y=2X+3+noise;Y=-3X+3+noise
X = tf.random.uniform([n,2],minval=-10,maxval=10) 
w0 = tf.constant([[2.0],[-2.0]])
b0 = tf.constant([[3.0]])
Y = X@w0 + b0 + tf.random.normal([n,1],mean = 0.0,stddev= 2.0)
复制代码


生成的数据长这样


plt.figure(figsize = (12,5))
ax1 = plt.subplot(121)
ax1.scatter(X[:,0],Y[:,0], c = "b")
plt.xlabel("x1")
plt.ylabel("y",rotation = 0)
ax2 = plt.subplot(122)
ax2.scatter(X[:,1],Y[:,0], c = "g")
plt.xlabel("x2")
plt.ylabel("y",rotation = 0)
plt.show()
复制代码


image.png


在这里为了简单起见,我就不划分训练集、测试集啥的,直接用全部数据训练加预测。接下来我们还需要构造一个数据生成器,用来生成每一个batch_size中的X和Y。

数据生成器的大致思路如下:


  1. 首先随机打乱数据下标
  2. 遍历数据,每一个batch_size作为一个分隔,得到打乱后的下标切片(大小为batch_size)
  3. 使用tf.gather()函数将X,Y分别和上一步得到的随机下标组合,yield返回生成器

tf.gather(params,indices,axis=0)函数是根据indices下标从params中返回对应元素的切片


# 构建数据生成器
# 其中tf.gather(params,indices,axis=0)是根据indices下标从params中返回对应元素的切片
def data_iter(features, labels, batch_size=8):
    num_examples = len(features)
    indices = list(range(num_examples))
    np.random.shuffle(indices)
    for i in range(0, num_examples, batch_size):
        indexs = indices[i: min(i + batch_size, num_examples)]
        yield tf.gather(features,indexs), tf.gather(labels,indexs)
# 测试数据生成器效果   
batch_size = 8
(datas,labels) = next(data_iter(X,Y,batch_size))
print(datas)
复制代码


image.png


到这里,数据生成以及构建生成器已经实现了,接下来就是定义并训练模型,也是今天的关键。


1.2 高阶API实现


首先,我想用大家最常见的写法来实现模型构建,这样可能不用涉及太多细节知识就可以简单搭建起来网络,放在开始更能让人接受。


在这里我设置学习率为0.001,batch_size=20,epochs=100,优化器选择SGD

在这里关于优化器,我想额外说几句。优化器作为参数优化的关键,在模型训练中的重要程度可想而知。大多时候我们选择Adam作为优化器,但是就最近我自己的实践结果来看,Adam拟合慢而且效果并不太好(这里的效果指的是最终的loss大小),达到同样的loss需要更多次的迭代训练,而且往往loss也高于SGD。然后我就去研究了一下近几年关于优化器所提出的新方法,比如AggMo、Apollo、diffGrad、Lamb、MADGRAD……我对于优化器有了更深的理解,同时也在思考有没有更好的优化器方法。当然,上面提到的一些方法不论是在Tensorflow还是Pytorch中的optimizers中都是没有对应API的,不过有人专门收集整理建了一个Pytorch兼容的优化器第三方库pytorch-optimizer,大家可以去试试新的优化器与经典的优化器之间效果上有什么不同。


好,回到今天的主题,开始搭建网络


这里我们已知方程是一个线性方程,所以只需要一层线性层拟合就可以了,也不用添加其他非线性的激活函数


lr3=0.001
optimizer=optimizers.SGD(learning_rate=lr3)
model3=models.Sequential()
model3.add(layers.Dense(1,input_shape=(2,)))
model3.compile(optimizer=optimizer,loss='mse',metrics=['mae'])
model3.fit(X,Y,batch_size=20,epochs=100)
tf.print(f"w={model3.layers[0].kernel}")
tf.print(f"b={model3.layers[0].bias}")
复制代码


image.png

最终loss在3.62,模型拟合效果如下


w,b = model3.variables
plt.figure(figsize = (12,5))
ax1 = plt.subplot(121)
ax1.scatter(X[:,0],Y[:,0], c = "b",label = "samples")
ax1.plot(X[:,0],w[0]*X[:,0]+b[0],"-r",linewidth = 5.0,label = "model")
ax1.legend()
plt.xlabel("x1")
plt.ylabel("y",rotation = 0)
ax2 = plt.subplot(122)
ax2.scatter(X[:,1],Y[:,0], c = "g",label = "samples")
ax2.plot(X[:,1],w[1]*X[:,1]+b[0],"-r",linewidth = 5.0,label = "model")
ax2.legend()
plt.xlabel("x2")
plt.ylabel("y",rotation = 0)
plt.show()


image.png


1.3 中阶API实现


高阶API实现最主要的特点就是方便简洁,几行代码就完成了模型的搭建训练,但是中阶的API使用就不再那么依赖封装好的接口,部分功能开始可以自己实现。


# 学习率
lr2=0.001
# 批次大小
batch_size2=30
model2=layers.Dense(1,input_shape=(2,))
model2.loss_func=losses.mean_squared_error
model2.optimizer=optimizers.SGD(learning_rate=lr2)
复制代码


和高级API实现一样,这里只是不再需要models,而是简单一层。设置好损失函数和优化器,接下来就是自己编写训练过程。


首先写一个epoch训练的函数,然后再用循环训练epochs次


@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1]))
    grads = tape.gradient(loss,model.variables)
    model.optimizer.apply_gradients(zip(grads,model.variables))
    return loss
# 测试train_step效果
features,labels = next(data_iter(X,Y,batch_size2))
train_step(model2,features,labels)
复制代码


借助之前说的自动求微分,我们正向得到每一次的预测值以及损失,然后根据损失对模型的参数求偏导数,得到每一个参数的梯度,最后优化器根据每个参数的梯度进行更新


image.png

有了对每一次epoch训练,然后只用循环就可以迭代训练模型了


def train_model(model,epochs):
    for epoch in tf.range(1,epochs+1):
        loss = tf.constant(0.0)
        for features, labels in data_iter(X,Y,batch_size2):
            loss = train_step(model,features,labels)
        if epoch%50==0:
            tf.print(f"=========================================================   {time.asctime(time.localtime(time.time()))}")
            tf.print("epoch =",epoch,"loss = ",loss)
            tf.print("w =",model.variables[0])
            tf.print("b =",model.variables[1])
train_model(model2,epochs = 200)
w,b = model2.variables
plt.figure(figsize = (12,5))
ax1 = plt.subplot(121)
ax1.scatter(X[:,0],Y[:,0], c = "b",label = "samples")
ax1.plot(X[:,0],w[0]*X[:,0]+b[0],"-r",linewidth = 5.0,label = "model")
ax1.legend()
plt.xlabel("x1")
plt.ylabel("y",rotation = 0)
ax2 = plt.subplot(122)
ax2.scatter(X[:,1],Y[:,0], c = "g",label = "samples")
ax2.plot(X[:,1],w[1]*X[:,1]+b[0],"-r",linewidth = 5.0,label = "model")
ax2.legend()
plt.xlabel("x2")
plt.ylabel("y",rotation = 0)
plt.show()


image.png


最终的loss在3.46左右


1.4 最基础API的实现


上面两种实现中Dense帮我们省去了构建y=w*x+by=wx+b

image.png


optimizer让我们可以不用自己去实现优化算法,下面不用任何封装,就用最基本的API以及一些基础知识去实现试试。

首先自己构造y=w∗x+by=w*x+by=wx+b,声明两个变量w,b,然后定义正向传播的计算公式x@w+bx@w+bx@w+b,这就是Dense中去掉激活函数而已;再定义损失函数,还是使用均方误差(groudtruth−predict)2N\frac{(groudtruth-predict)^2}{N}N(groudtruthpredict)2,为了求导之后把指数消掉,通常前面再乘以一个12\frac{1}{2}21


# 构建wx+b拟合函数
w = tf.Variable(tf.random.normal(w0.shape))
b = tf.Variable(tf.zeros_like(b0,dtype = tf.float32))
# 定义模型
class LinearRegression:     
    #正向传播
    def __call__(self,x): 
        return x@w + b
    # 损失函数
    def loss_func(self,y_true,y_pred):  
        return tf.reduce_mean((y_true - y_pred)**2/2)
model = LinearRegression()
复制代码


这样,一个基本的线性回归模型就建立好了,接下来就是优化模型参数的阶段,也就是训练模型。模型的参数量不大,所以我们这里就用最基础的梯度下降法。其中梯度依靠自动求导,梯度更新公式为:w=w−α∗∂∂wJ(w,b)w=w-\alpha*\frac{\partial}{\partial w}J(w,b)w=wαwJ(w,b)

其中www为权重,α\alphaα为学习率也就是每次更新下降的步长,J(w,b)J(w,b)J(w,b)是损失函数即上面的均方误差,其他训练部分和上面的训练部分类似


# 学习率
lr=0.001
# 批次大小
batch_size=20
@tf.function
def train_step(model, features, labels):
    # 用于自动微分
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(labels, predictions)
    # 反向传播求梯度,即各系数的偏导数
    dloss_dw,dloss_db = tape.gradient(loss,[w,b])
    # 梯度下降法更新参数
    w.assign(w - lr*dloss_dw)
    b.assign(b - lr*dloss_db)
    return loss
def train_model(model,epochs):
    for epoch in tf.range(1,epochs+1):
        for features, labels in data_iter(X,Y,batch_size):
            loss = train_step(model,features,labels)
        if epoch%50==0:
            tf.print(f"=========================================================   {time.asctime(time.localtime(time.time()))}")
            tf.print("epoch =",epoch,"loss = ",loss)
            tf.print("w =",w)
            tf.print("b =",b)
train_model(model,epochs = 200)
复制代码


image.png

最终的loss竟然只有2.00左右,自己一个简单的梯度下降效果比其他高级的优化器效果更好,也许是方程太简单。


2. 分类问题


分类问题和回归问题流程大致类似,还是先生成数据,然后用API搭建模型并训练。唯一的不同之处在于回归问题由于是线性分布,不需要激活函数,训练时使用梯度下降也能很好的收敛拟合;但是分类时是非线性的,所以必须在每一层添加激活函数,并且训练的时候损失函数就不再是MSE了,而是使用交叉熵作为损失函数。


为什么MSE不再适用?


image.png

这是Sigmoid激活函数的原函数曲线和它的导数曲线,如果我们使用MSE作为损失函数,一开始MSE如果很大(往往都是这样),那么在一开始Sigmoid函数的导数值几乎为0,这个时候梯度下降几乎没有梯度(梯度消失),也就无法进行参数更新,最终训练失败。

这个时候交叉熵就是一个很好的分类损失函数


H(p,q)=−∑i=1np(xi)log(q(xi))H(p,q)=-\sum_{i=1}^{n}p(x_i)log(q(x_i))H(p,q)=i=1np(xi)log(q(xi))

其中p(xi)p(x_i)p(xi)是事件发生的概率,q(xi)q(x_i)q(xi)是预测概率

对于二分类来说,只有0或者1两种标签,然后q=1-p,于是上面的公式可以简化为

Cross_Entropy(p,q)=−(plogq+(1−p)log(1−q))Cross\_Entropy(p,q)=-(plog{q}+(1-p)log(1-q))Cross_Entropy(p,q)=(plogq+(1p)log(1q))

说了基本的原理,现在就开始实现


2.1 数据生成


#正负样本数量
n_positive,n_negative = 2000,2000
#生成正样本, 小圆环分布
r_p = 5.0 + tf.random.truncated_normal([n_positive,1],0.0,1.0)
theta_p = tf.random.uniform([n_positive,1],0.0,2*np.pi) 
Xp = tf.concat([r_p*tf.cos(theta_p),r_p*tf.sin(theta_p)],axis = 1)
Yp = tf.ones_like(r_p)
#生成负样本, 大圆环分布
r_n = 8.0 + tf.random.truncated_normal([n_negative,1],0.0,1.0)
theta_n = tf.random.uniform([n_negative,1],0.0,2*np.pi) 
Xn = tf.concat([r_n*tf.cos(theta_n),r_n*tf.sin(theta_n)],axis = 1)
Yn = tf.zeros_like(r_n)
#汇总样本
X = tf.concat([Xp,Xn],axis = 0)
Y = tf.concat([Yp,Yn],axis = 0)
#可视化
plt.figure(figsize = (6,6))
plt.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r")
plt.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g")
plt.legend(["正样本","负样本"])
plt.show()
复制代码


tf.random.truncated_normal()函数是截断正态分布,也就是限定随机生成正态分布数据的范围在(μ−2δ,μ+2δ)(\mu-2\delta,\mu+2\delta)(μ2δ,μ+2δ),最终的样本长这样


image.png


2.2 高阶API实现


使用高级API依然还是几行代码就可以实现


model3=models.Sequential()
model3.add(layers.Dense(4,input_shape=(2,),activation='relu'))
model3.add(layers.Dense(8,activation='relu'))
model3.add(layers.Dense(1,activation='sigmoid'))
model3.summary()
复制代码


image.png


optimizer = optimizers.SGD(learning_rate=0.001)
loss_func = tf.keras.losses.BinaryCrossentropy()
model3.compile(optimizer=optimizer,loss=loss_func,metrics=['acc'])
model3.fit(X,Y,batch_size=100,epochs=50)
fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5))
ax1.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r")
ax1.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g")
ax1.legend(["positive","negative"]);
ax1.set_title("y_true");
Xp_pred = tf.boolean_mask(X,tf.squeeze(model3(X)>=0.5),axis = 0)
Xn_pred = tf.boolean_mask(X,tf.squeeze(model3(X)<0.5),axis = 0)
ax2.scatter(Xp_pred[:,0].numpy(),Xp_pred[:,1].numpy(),c = "r")
ax2.scatter(Xn_pred[:,0].numpy(),Xn_pred[:,1].numpy(),c = "g")
ax2.legend(["positive","negative"]);
ax2.set_title("y_pred")
plt.show()
复制代码

image.png


2.3 中阶API实现


使用中阶API主要就是不再依赖models.Sequential(),自己定义深度神经网络,然后写好里面的各层以及正向传播。实例化之后再用二元交叉熵以及优化器去优化,训练模型


class DNNModel2(tf.Module):
    def __init__(self,name = None):
        super(DNNModel2, self).__init__(name=name)
        self.dense1 = layers.Dense(4,activation = "relu") 
        self.dense2 = layers.Dense(8,activation = "relu")
        self.dense3 = layers.Dense(1,activation = "sigmoid")
    # 正向传播
    @tf.function(input_signature=[tf.TensorSpec(shape = [None,2], dtype = tf.float32)])  
    def __call__(self,x):
        x = self.dense1(x)
        x = self.dense2(x)
        y = self.dense3(x)
        return y
model2 = DNNModel2()
model2.loss_func = losses.binary_crossentropy
model2.metric_func = metrics.binary_accuracy
model2.optimizer = optimizers.Adam(learning_rate=0.001)
(features,labels) = next(data_iter(X,Y,batch_size))
predictions = model2(features)
loss = model2.loss_func(tf.reshape(labels,[-1]),tf.reshape(predictions,[-1]))
metric = model2.metric_func(tf.reshape(labels,[-1]),tf.reshape(predictions,[-1]))
tf.print("初始损失:",loss)
tf.print("初始化准确率",metric)
复制代码

模型的训练方式和上面的回归问题相似


@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1]))
    grads = tape.gradient(loss,model.trainable_variables)
    model.optimizer.apply_gradients(zip(grads,model.trainable_variables))
    metric = model.metric_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1]))
    return loss,metric
# 测试train_step效果
(features,labels) = next(data_iter(X,Y,batch_size))
train_step(model2,features,labels)
def train_model(model,epochs):
    for epoch in tf.range(1,epochs+1):
        loss, metric = tf.constant(0.0),tf.constant(0.0)
        for features, labels in data_iter(X,Y,batch_size):
            loss,metric = train_step(model,features,labels)
        if epoch%10==0:
            tf.print(f"=========================================================   {time.asctime(time.localtime(time.time()))}")
            tf.print("epoch =",epoch,"loss = ",loss, "accuracy = ",metric)
train_model(model2,epochs = 50)
fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5))
ax1.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r")
ax1.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g")
ax1.legend(["positive","negative"]);
ax1.set_title("y_true");
Xp_pred = tf.boolean_mask(X,tf.squeeze(model2(X)>=0.5),axis = 0)
Xn_pred = tf.boolean_mask(X,tf.squeeze(model2(X)<0.5),axis = 0)
ax2.scatter(Xp_pred[:,0].numpy(),Xp_pred[:,1].numpy(),c = "r")
ax2.scatter(Xn_pred[:,0].numpy(),Xn_pred[:,1].numpy(),c = "g")
ax2.legend(["positive","negative"]);
ax2.set_title("y_pred")
plt.show()


image.png

2.4 低阶API实现


上面实现中除了最后分类层以外每一个层其实都只是在完成一件事,即计算Y=relu(w∗x+b)Y=relu(w*x+b)Y=relu(wx+b),最后一层为了分类将relu改成sigmoid,其他不变;所以我们在低级实现中,老老实实定义变量,然后前向传播,反向计算更新这些参数。然后loss_func也就是二元交叉熵就用我们一开始讲的简化公式


class DNNModel(tf.Module):
    def __init__(self,name = None):
        super(DNNModel, self).__init__(name=name)
        self.w1 = tf.Variable(tf.random.truncated_normal([2,4]),dtype = tf.float32)
        self.b1 = tf.Variable(tf.zeros([1,4]),dtype = tf.float32)
        self.w2 = tf.Variable(tf.random.truncated_normal([4,8]),dtype = tf.float32)
        self.b2 = tf.Variable(tf.zeros([1,8]),dtype = tf.float32)
        self.w3 = tf.Variable(tf.random.truncated_normal([8,1]),dtype = tf.float32)
        self.b3 = tf.Variable(tf.zeros([1,1]),dtype = tf.float32)
    # 正向传播
    @tf.function(input_signature=[tf.TensorSpec(shape = [None,2], dtype = tf.float32)])  
    def __call__(self,x):
        x = tf.nn.relu(x@self.w1 + self.b1)
        x = tf.nn.relu(x@self.w2 + self.b2)
        y = tf.nn.sigmoid(x@self.w3 + self.b3)
        return y
    # 损失函数(二元交叉熵)
    @tf.function(input_signature=[tf.TensorSpec(shape = [None,1], dtype = tf.float32),
                              tf.TensorSpec(shape = [None,1], dtype = tf.float32)])  
    def loss_func(self,y_true,y_pred):  
        #将预测值限制在 1e-7 以上, 1 - 1e-7 以下,避免log(0)错误
        eps = 1e-7
        y_pred = tf.clip_by_value(y_pred,eps,1.0-eps)
        bce = - y_true*tf.math.log(y_pred) - (1-y_true)*tf.math.log(1-y_pred)
        return  tf.reduce_mean(bce)
    # 评估指标(准确率)
    @tf.function(input_signature=[tf.TensorSpec(shape = [None,1], dtype = tf.float32),
                              tf.TensorSpec(shape = [None,1], dtype = tf.float32)]) 
    def metric_func(self,y_true,y_pred):
        y_pred = tf.where(y_pred>0.5,tf.ones_like(y_pred,dtype = tf.float32),
                          tf.zeros_like(y_pred,dtype = tf.float32))
        acc = tf.reduce_mean(1-tf.abs(y_true-y_pred))
        return acc
batch_size = 10
(features,labels) = next(data_iter(X,Y,batch_size))
# 模型实例化
model = DNNModel()
predictions = model(features)
loss = model.loss_func(labels,predictions)
metric = model.metric_func(labels,predictions)
tf.print("初始损失:",loss)
tf.print("初始化准确率",metric)
复制代码


image.png

根据loss_func对所有可训练参数,也就是我们自己定义的那些参数进行训练,更新方式依旧是w=w−α∗∂∂ww=w-\alpha *\frac{\partial}{\partial w}w=wαw


# 开始训练
lr=0.005
@tf.function
def train_step(model, features, labels):
    # 正向传播求损失
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(labels, predictions) 
    # 反向传播求梯度
    grads = tape.gradient(loss, model.trainable_variables)
    # 执行梯度下降
    for p, dloss_dp in zip(model.trainable_variables,grads):
        p.assign(p - lr*dloss_dp)
    # 计算评估指标
    metric = model.metric_func(labels,predictions)
    return loss, metric
def train_model(model,epochs):
    for epoch in tf.range(1,epochs+1):
        for features, labels in data_iter(X,Y,150):
            loss,metric = train_step(model,features,labels)
        if epoch%100==0:
            tf.print(f"=========================================================   {time.asctime(time.localtime(time.time()))}")
            tf.print("epoch =",epoch,"loss = ",loss, "accuracy = ", metric)
train_model(model,epochs = 600)
fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5))
ax1.scatter(Xp[:,0],Xp[:,1],c = "r")
ax1.scatter(Xn[:,0],Xn[:,1],c = "g")
ax1.legend(["positive","negative"]);
ax1.set_title("y_true");
Xp_pred = tf.boolean_mask(X,tf.squeeze(model(X)>=0.5),axis = 0)
Xn_pred = tf.boolean_mask(X,tf.squeeze(model(X)<0.5),axis = 0)
ax2.scatter(Xp_pred[:,0],Xp_pred[:,1],c = "r")
ax2.scatter(Xn_pred[:,0],Xn_pred[:,1],c = "g")
ax2.legend(["positive","negative"]);
ax2.set_title("y_pred")
plt.show()
复制代码


image.png


结束


今天算是把如何搭建一个模型重新复习了一遍,其中有一些重要的细节比如input_shape的大小还有Dense中的值的含义,这些常用的API会在后续细细的讲。这么多种模型搭建方式,复习一遍之后对调参技巧更加熟练,加深了对模型实现原理的理解。进度比我预期的还是慢了一点,之后应该还要加快点。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
16天前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
60 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
2月前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
34 1
|
2月前
|
机器学习/深度学习 人工智能 PyTorch
AI智能体研发之路-模型篇(五):pytorch vs tensorflow框架DNN网络结构源码级对比
AI智能体研发之路-模型篇(五):pytorch vs tensorflow框架DNN网络结构源码级对比
62 1
|
2月前
|
测试技术 数据库
探索JSF单元测试秘籍!如何让您的应用更稳固、更高效?揭秘成功背后的测试之道!
【8月更文挑战第31天】在 JavaServer Faces(JSF)应用开发中,确保代码质量和可维护性至关重要。本文详细介绍了如何通过单元测试实现这一目标。首先,阐述了单元测试的重要性及其对应用稳定性的影响;其次,提出了提高 JSF 应用可测试性的设计建议,如避免直接访问外部资源和使用依赖注入;最后,通过一个具体的 `UserBean` 示例,展示了如何利用 JUnit 和 Mockito 框架编写有效的单元测试。通过这些方法,不仅能够确保代码质量,还能提高开发效率和降低维护成本。
44 0
|
2月前
|
UED 开发者
哇塞!Uno Platform 数据绑定超全技巧大揭秘!从基础绑定到高级转换,优化性能让你的开发如虎添翼
【8月更文挑战第31天】在开发过程中,数据绑定是连接数据模型与用户界面的关键环节,可实现数据自动更新。Uno Platform 提供了简洁高效的数据绑定方式,使属性变化时 UI 自动同步更新。通过示例展示了基本绑定方法及使用 `Converter` 转换数据的高级技巧,如将年龄转换为格式化字符串。此外,还可利用 `BindingMode.OneTime` 提升性能。掌握这些技巧能显著提高开发效率并优化用户体验。
44 0
|
2月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
57 0
|
2月前
|
C# 开发者 前端开发
揭秘混合开发新趋势:Uno Platform携手Blazor,教你一步到位实现跨平台应用,代码复用不再是梦!
【8月更文挑战第31天】随着前端技术的发展,混合开发日益受到开发者青睐。本文详述了如何结合.NET生态下的两大框架——Uno Platform与Blazor,进行高效混合开发。Uno Platform基于WebAssembly和WebGL技术,支持跨平台应用构建;Blazor则让C#成为可能的前端开发语言,实现了客户端与服务器端逻辑共享。二者结合不仅提升了代码复用率与跨平台能力,还简化了项目维护并增强了Web应用性能。文中提供了从环境搭建到示例代码的具体步骤,并展示了如何创建一个简单的计数器应用,帮助读者快速上手混合开发。
45 0
|
2月前
|
开发者 算法 虚拟化
惊爆!Uno Platform 调试与性能分析终极攻略,从工具运用到代码优化,带你攻克开发难题成就完美应用
【8月更文挑战第31天】在 Uno Platform 中,调试可通过 Visual Studio 设置断点和逐步执行代码实现,同时浏览器开发者工具有助于 Web 版本调试。性能分析则利用 Visual Studio 的性能分析器检查 CPU 和内存使用情况,还可通过记录时间戳进行简单分析。优化性能涉及代码逻辑优化、资源管理和用户界面简化,综合利用平台提供的工具和技术,确保应用高效稳定运行。
40 0
|
2月前
|
前端开发 开发者 设计模式
揭秘Uno Platform状态管理之道:INotifyPropertyChanged、依赖注入、MVVM大对决,帮你找到最佳策略!
【8月更文挑战第31天】本文对比分析了 Uno Platform 中的关键状态管理策略,包括内置的 INotifyPropertyChanged、依赖注入及 MVVM 框架。INotifyPropertyChanged 方案简单易用,适合小型项目;依赖注入则更灵活,支持状态共享与持久化,适用于复杂场景;MVVM 框架通过分离视图、视图模型和模型,使状态管理更清晰,适合大型项目。开发者可根据项目需求和技术栈选择合适的状态管理方案,以实现高效管理。
32 0
|
2月前
|
Apache 开发者 Java
Apache Wicket揭秘:如何巧妙利用模型与表单机制,实现Web应用高效开发?
【8月更文挑战第31天】本文深入探讨了Apache Wicket的模型与表单处理机制。Wicket作为一个组件化的Java Web框架,提供了多种模型实现,如CompoundPropertyModel等,充当组件与数据间的桥梁。文章通过示例介绍了模型创建及使用方法,并详细讲解了表单组件、提交处理及验证机制,帮助开发者更好地理解如何利用Wicket构建高效、易维护的Web应用程序。
28 0

热门文章

最新文章

下一篇
无影云桌面