分别基于Tensorflow和Keras加载预训练模型实现迁移学习

快速将Keras模型转换成Tensorflow模型 本文介绍将keras模型转换成Tensorflow模型的方法 阅读详情

1.什么迁移学习和预训练模型?

迁移学习(Tranfer Learning):神经网络可以从一个任务中习得知识,并将这些知识应用到另一个独立的任务中。所以例如,也许你已经训练好一个神经网络,能够识别像猫这样的对象,然后使用那些知识,或者部分习得的知识去帮助您更好地阅读x射线扫描图,这就是所谓的迁移学习。
预训练(pre-training):如果你有一个小数据集,就只训练输出层前的最后一层,或者也许是最后一两层。但是如果你有很多数据,那么也许你可以重新训练网络中的所有参数。如果你重新训练神经网络中的所有参数,那么这个在图像识别数据的初期训练阶段,有时称为预训练(pre-training),而其所保存的模型就是预训练模型(pre-training model)。
**微调(fine tuning):**当我们使用预训练神经网络的权重,然后如果你以后更新所有权重,那么这个过程就是微调。

2.实现迁移学习的方法及使用场景

(1)特征提取:
我们可以将预训练模型当做特征提取装置来使用。具体的做法是,将输出层或者全连接层去掉,然后将剩下的整个网络当做一个固定的特征提取机,然后应用到我们的模型中。
**适用情景:**数据集小,数据相识度较高。在这种情况下,因为数据与预训练模型的训练数据相似度很高,因此我们不需要重新训练模型,我们使用预处理模型作为模式提取器。

(2)训练特定层,冻结其它层:
具体的做法是,将模型起始的一些层的权重保持不变,重新训练后面的层,得到新的权重。
**适用场景:**数据集小,数据相识度不高。在这种情况下,我们可以冻结预训练模型中的前k个层中的权重,然后重新训练后面的n-k个层,当然最后一层也需要根据相应的输出格式来进行修改。

3.python代码实现

这里我们用vgg16作为我们的预训练模型。

3.1特征提取

3.1.1基于keras实现

这里用mnist数据集实现手写数字体识别为例。
(1)特征提取:

def extract_features(input_x):
    m = input_x.shape[0]
    #include_top=False 去掉表示去掉vgg16网络后面的全连接层
    model = VGG16(weights='imagenet', include_top=False)
    #然后进行预测输出不包含全连接层提取的特征
    features_train = model.predict(input_x)
    train_x = features_train.reshape(m, -1)

    return train_x

这里我们是通过keras加载vgg16的模型,但是在本机上比较慢,可以现在网上下载好模型,然后放到C:\Users\Administrator.keras的文件下,每个人可能不一样。
下载地址:https://github.com/fchollet/deep-learning-models/releases
在这里插入图片描述

这里我们可以对比一下去掉全连接层的网络和未去掉的:

from keras.applications.vgg16 import VGG16
#去掉全连接层
model = VGG16(weights='imagenet', include_top=False)
model.summary()
#完整的vgg16网络
model = VGG16(weights='imagenet')
model.summary()

输出结果太长这里就不放出来了。

(2)创建我们自己的网络,是前面vgg16卷积层的输出作为我们网络的输入。
注意当全连接层作为第一层的时候,需要指明输入维度input_dim,这个根据我们特征提取的输出维度而决定。

def my_model(num_classes = 10):

    model = Sequential()
    model.add(Dense(1000, input_dim=2048, activation='relu', kernel_initializer='uniform'))
    model.add(Dropout(0.3))

    model.add(Dense(500, input_dim=1000, activation='sigmoid'))
    model.add(Dropout(0.4))

    model.add(Dense(150, input_dim=500, activation='sigmoid'))
    model.add(Dropout(0.2))

    model.add(Dense(units=num_classes))
    model.add(Activation('softmax'))

    return model

完整代码:

from keras.models import Sequential, load_model
import matplotlib.pyplot as plt
import numpy as np
import keras
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
import numpy as np
from keras.layers import Dense, Activation, Dropout, Flatten,Input
from sklearn.model_selection import train_test_split
from pretrain_project.utils import load_grabage_dataset, convert_to_one_hot
import cv2

def my_model(num_classes = 10):

    model = Sequential()
    model.add(Dense(1000, input_dim= 4608,activation='relu'))
    model.add(Dropout(0.3))

    model.add(Dense(500, activation='relu'))
    model.add(Dropout(0.4))

    model.add(Dense(150, activation='relu'))
    model.add(Dropout(0.2))

    model.add(Dense(units=num_classes))
    model.add(Activation('softmax'))

    return model

def extract_features(input_x):
    # include_top=False 去掉顶部的全连接层
    m = input_x.shape[0]
    model = VGG16(weights='imagenet', include_top=False)
    # model.summary()
    features_train = model.predict(input_x)
    train_x = features_train.reshape(m, -1)

    return train_x
                 
def predict(input_x):
    input_x = input_x.reshape(-1,96,96,3)
    input_x = extract_features(input_x)
    model = load_model("model/garbage_model.h5")
    preds_prob = model.predict(input_x)
    print(preds_prob)
    preds = np.argmax(preds_prob, 1)[0]
    print("预测结果:",grabage_classes[preds])

# 加载训练集
from keras.datasets import mnist
(train_x, train_y), (test_x, test_y) = mnist.load_data()

#将灰度图中的单通道转为RGB多通道
train_x = np.array(train_x, dtype="uint8")
train_x = [cv2.cvtColor(cv2.resize(x, (64, 64)), cv2.COLOR_GRAY2BGR) for x in train_x]
train_x = np.concatenate([arr[np.newaxis] for arr in train_x]).astype('float32')

train_y = train_y.reshape(len(train_y),1).astype(int)
train_y = convert_to_one_hot(train_y,10)

#进行特征提取
train_x = extract_features(train_x)
print(train_x.shape)
#训练模型
model = my_model(num_classes=10)
model.compile(loss='categorical_crossentropy', optimizer="adam", metrics=['accuracy'])
model.fit(train_x, train_y, epochs=20, batch_size=64)
model.save("model/my_model.h5")

我们这里把图片的大小放大为64x64,因为28x28太小了,经过卷积层后维度就成负了

运行结果(这里省略了一部分,太多了):

Epoch 16/20
1000/1000 [==============================] - 0s 83us/step - loss: 0.0739 - acc: 0.9800
Epoch 17/20
1000/1000 [==============================] - 0s 81us/step - loss: 0.0712 - acc: 0.9790
Epoch 18/20
1000/1000 [==============================] - 0s 83us/step - loss: 0.0698 - acc: 0.9820
Epoch 19/20
1000/1000 [==============================] - 0s 93us/step - loss: 0.0632 - acc: 0.9870
Epoch 20/20
1000/1000 [==============================] - 0s 90us/step - loss: 0.0514 - acc: 0.9860
3.1.2基于tensorflow实现

总体来说基于keras的实现更加简洁,省去了前向传播的代码,我们只需要搭建好网络即可,而tensorflow相对于keras实现的代码会更多一些,但是作为都是很流行的框架,因此还是有比较都掌握的。

首先我们需要下载vgg权重文件,因为tensorflow没有向keras那样提供直接的方法。
预训练模型下载链接:(https://github.com/tensorflow/models/tree/1af55e018eebce03fb61bba9959a04672536107d/research/slim)
在这里插入图片描述

(1)首先先构建我们的vgg16网络结构,因为我并没有找到vgg16的.meta文件(即网络结构),我们下载的只有.ckpt权重文件,具体的网络结构也可以通过点击上图的Code源码进行查看。

def vgg16(inputs):
    with slim.arg_scope([slim.conv2d, slim.fully_connected],activation_fn=tf.nn.relu,weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),weights_regularizer=slim.l2_regularizer(0.0005)):
        net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
        net = slim.max_pool2d(net1, [2, 2], scope='pool1')
        net = slim.repeat(net2, 2, slim.conv2d, 128, [3, 3], scope='conv2')
        net = slim.max_pool2d(net3, [2, 2], scope='pool2')
        net = slim.repeat(net4, 3, slim.conv2d, 256, [3, 3], scope='conv3')
        net = slim.max_pool2d(net5, [2, 2], scope='pool3')
        net = slim.repeat(net6, 3, slim.conv2d, 512, [3, 3], scope='conv4')
        net = slim.max_pool2d(net7, [2, 2], scope='pool4')
        net = slim.repeat(net8, 3, slim.conv2d, 512, [3, 3], scope='conv5')
        net = slim.max_pool2d(net9, [2, 2], scope='pool5')
        return net

补充1:

tf.contrib.slim他是可以帮助我们更加快捷的搭建我们的网络结构,例如上面我们的vgg16网络结构,中间可能涉及连续的卷积层,按照我们常规的写法,则我们的代码会存在很多重复,而使用slim则会简洁很多。
例如net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope=‘conv1’),第一个参数是我们的输入,第二个参数是我们重复的次数,第三个则是我们要用的层,第四个和第五个参数是我们重复的每一层的卷积核数量和大小,第五个就是scope,可用于指定这一层的变量的范围。

补充2:

关于我们构建的网络是怎么从权重文件中获取对应权重的呢?这个就是变量名来决定的,至于这个变量名我们则需要查看上图中的Code源码进行查看,这就是我们在定义模型时指定scope的原因,就是为了和权重文件中对应权重的名称匹配。
slim.arg_scope函数的作用主要就是为目标函数(上面是slim.conv2d, slim.fully_connected)设置默认超参数(activation_fn等…),因为我们的卷积层中可能会有重复的超参数,这样在slim.arg_scope就可以简化我们的代码,如果我们某一层不需要默认的参数,则是需要在那一层重新传入即可。

(2)特征提取:

def extract_features(inputs):
    input_image = tf.placeholder(tf.float32, shape=[None, None, None, 3], name='input_image')
    with tf.variable_scope('vgg_16', reuse=tf.AUTO_REUSE):
        model = vgg16(input_image)
    variable_restore_op = slim.assign_from_checkpoint_fn("pretrain_models/vgg_16.ckpt",
                                                         slim.get_trainable_variables(),
                                                         ignore_missing_vars=True)
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        variable_restore_op(sess)
        feature_x = sess.run(model, feed_dict={input_image:inputs})

    return feature_x

这里就是导入我们的预训练模型的权重,slim.assign_from_checkpoint_fn的第一个参数就是我们权重文件的路径,第二个参数是我们要把权重文件中的权重恢复到哪些变量上面,第三个参数ignore_missing_vars设为true的意义是忽略那些在定义的模型结构中可能存在的而在预训练模型中没有的变量。
然后通过传进来的数据集,在sess下运行,输出我们通过卷积层提取到的特征。

(3)拿到特征后,接着需要构建我们自己的模型,这就是基本的用TensorFlow训练模型的步骤,w我们只需要把经过上面特征提取的数据集作为模型的输入进行训练即可。可以看一下上一篇博客基于tensorflow的手写数字体识别:

def create_placeholders(n_H0, n_W0, n_C0, n_y):
    X = tf.placeholder(tf.float32, [None, n_H0, n_W0, n_C0])
    Y = tf.placeholder(tf.float32, [None, n_y])

    return X, Y

def forward_propagation(inputs):
    a = tf.contrib.layers.flatten(inputs)
    #fc1
    a1 = tf.contrib.layers.fully_connected(a, 4608)
    ad1 = tf.nn.dropout(a1,0.5)
    #fc2
    a2 = tf.contrib.layers.fully_connected(ad1, 1000)
    ad2 = tf.nn.dropout(a2, 0.5)
    #outputs
    z3 = tf.contrib.layers.fully_connected(ad2, 10, activation_fn=None)
    return z3

def compute_cost(Z3, Y):
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=Z3,labels=Y))
    return cost

def my_model(X_train, Y_train, X_test, Y_test, learning_rate=0.0001,num_epochs=30,minibatch_size=64,print_cost=True,isPlot=True):

    tf.reset_default_graph()
    tf.set_random_seed(1)
    seed = 3

    (m, n_H0, n_W0, n_C0) = X_train.shape
    n_y = Y_train.shape[1]
    costs = []
    X, Y = create_placeholders(n_H0,n_W0,n_C0,n_y)
    Z3 = forward_propagation(X)
    cost = compute_cost(Z3, Y)
    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

    init = tf.global_variables_initializer()
    saver = tf.train.Saver()
    total_time = 0

    with tf.Session() as sess:
        sess.run(init)
        for epoch in range(1,num_epochs+1):
            #每一迭代的开始时间
            start_time = time.clock()
            #每一次迭代中所有batch的代价,即总的代价
            minibatches_cost = 0

            num_minibatches = int(m / minibatch_size)
            #将我们的数据随机打乱并根据batch_size随机分成若干个batch
            minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)

            for minibatch in minibatches:
                (minibatch_X, minibatch_Y) = minibatch
                _, temp_cost = sess.run([optimizer, cost], feed_dict={X: minibatch_X, Y:minibatch_Y})
                minibatches_cost += temp_cost/num_minibatches

            end_time = time.clock()
            total_time += (end_time - start_time)
            if print_cost:
                if epoch % 10 == 0:
                    print("当前是第 " + str(epoch) + " 代,成本值为:" + str(minibatches_cost) + " ; 每一个epoch花费时间:" + str(
                        end_time - start_time) + " 秒,10个epoch总的时间:" + str(total_time))
                    total_time = 0

            if epoch % 10 == 0:
                costs.append(minibatches_cost)

        saver.save(sess, "model_tf/my-model")
        if isPlot:
            plt.plot(np.squeeze(costs))
            plt.ylabel("cost")
            plt.xlabel("iterations (per tens)")
            plt.title("Learning rate =" + str(learning_rate))
            plt.show()

        predict_op = tf.argmax(Z3, 1)
        corrent_prediction = tf.equal(predict_op, tf.argmax(Y, 1))

        accuracy = tf.reduce_mean(tf.cast(corrent_prediction, "float"))

        train_accuracy = accuracy.eval({X: X_train, Y: Y_train})
        test_accuracy = accuracy.eval({X: X_test, Y: Y_test})

        print("训练集准确度:" + str(train_accuracy))
        print("测试及准确度:" + str(test_accuracy))

    return (train_accuracy, test_accuracy)

3.2训练特定层,冻结其它层

3.2.1基于keras的实现

先看一下完整代码:

import matplotlib.pyplot as plt
import numpy as np
import keras
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
from keras.applications.vgg16 import decode_predictions
from keras.utils.np_utils import to_categorical
from sklearn.preprocessing import LabelEncoder
from keras.models import Sequential
from keras.optimizers import SGD
from keras.layers import Input, Dense, Convolution2D, MaxPooling2D
from sklearn.metrics import log_loss
from keras.models import Model
import cv2

def convert_to_one_hot(Y, C):
    Y = np.eye(C)[Y.reshape(-1)]
    return Y

def vgg16_model( num_classes=None):
	
    model = VGG16(weights='imagenet', include_top=True)
    model.layers.pop()
    #获取最后一层的输出
    #修改模型的输出为当前的最后一层,因为前面已经把模型的输出层pop掉了
    output = model.layers[-1].output
    #添加softmax层
    x = Dense(num_classes, activation='softmax')(output)
    model = Model(inputs=model.input, outputs=x)
    #冻结前8层,不训练
    for layer in model.layers[:8]:
        layer.trainable = False

    sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True)
    model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])

    return model
#加载数据集
from keras.datasets import mnist
(train_x, train_y), (test_x, test_y) = mnist.load_data()
train_x = train_x[:10000]
train_y = train_y[:10000]
train_x = np.array(train_x, dtype="uint8")

#将灰度图中的单通道转为RGB多通道
train_x = [cv2.cvtColor(cv2.resize(x, (224, 224)), cv2.COLOR_GRAY2BGR) for x in train_x]
train_x = np.concatenate([arr[np.newaxis] for arr in train_x]).astype('float32')

train_y = train_y.reshape(len(train_y),1).astype(int)
train_y = convert_to_one_hot(train_y,10)

print("训练集:")
print(train_x.shape)
print(train_y.shape)

model = vgg16_model(num_classes=10)
model.fit(train_x, train_y, batch_size=64, epochs=20, shuffle=True)
# model.save("minist_model/mnist_model.h5")

和3.1中的不一样,在这里我们导入的是包含全连接层的完整的vgg16,在这里我们只是冻结网络的前8层不训练,后面的依然用预训练模型的权重进行初始化。

这里需要注意的一点:

使用完整的网络结构,冻结部分层,训练其它层这种方法和特征提取不一样,特征提取我们的输入的图片大小可以任意(只要满足经过所有卷积层后大小不为负就行);而冻结部分层这种方法因为我们使用的完整的网络结构,需要训练的层用到了预训练模型的权重进行初始化,如果我们输入的维度和预训练模型的维度不同,那么在经过全连接层的时候,输入和全连接层的权重维度匹配就会出错。
所以在这里我们需要把图片转为223x224x3

3.2.2基于tensorflow的实现

先看完整代码:

import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import time
slim = tf.contrib.slim

import os
import h5py
import math
from keras.preprocessing import image
from keras.applications.imagenet_utils import preprocess_input
import cv2
import random

def convert_to_one_hot(Y, C):
    Y = np.eye(C)[Y.reshape(-1)]
    return Y

def random_mini_batches(X, Y, mini_batch_size = 64, seed = 0):

    m = X.shape[0]                  # number of training examples
    mini_batches = []
    np.random.seed(seed)
    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[permutation,:,:,:]
    shuffled_Y = Y[permutation,:]
    # Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.
    num_complete_minibatches = math.floor(m/mini_batch_size) # number of mini batches of size mini_batch_size in your partitionning
    for k in range(0, num_complete_minibatches):
        mini_batch_X = shuffled_X[k * mini_batch_size : k * mini_batch_size + mini_batch_size,:,:,:]
        mini_batch_Y = shuffled_Y[k * mini_batch_size : k * mini_batch_size + mini_batch_size,:]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)
    # Handling the end case (last mini-batch < mini_batch_size)
    if m % mini_batch_size != 0:
        mini_batch_X = shuffled_X[num_complete_minibatches * mini_batch_size : m,:,:,:]
        mini_batch_Y = shuffled_Y[num_complete_minibatches * mini_batch_size : m,:]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)
    return mini_batches

def vgg16(inputs):

    with slim.arg_scope([slim.conv2d, slim.fully_connected],activation_fn=tf.nn.relu,weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),weights_regularizer=slim.l2_regularizer(0.0005)):
        net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
        net = slim.max_pool2d(net, [2, 2], scope='pool1')
        net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2')
        net = slim.max_pool2d(net, [2, 2], scope='pool2')
        net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
        net = slim.max_pool2d(net, [2, 2], scope='pool3')
        net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv4')
        net = slim.max_pool2d(net, [2, 2], scope='pool4')
        net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv5')
        net = slim.max_pool2d(net, [2, 2], scope='pool5')
        # net = tf.contrib.layers.flatten(net)
        # net = slim.fully_connected(net, 4096, scope='fc6')
        net = slim.conv2d(net, 4096, [7, 7], padding="VALID", scope='fc6')
        net = slim.dropout(net, 0.5, scope='dropout6')
        # net = slim.fully_connected(net, 4096, scope='fc7')
        net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
        net = slim.dropout(net, 0.5, scope='dropout7')
        net = slim.conv2d(net, 10,[1, 1], activation_fn=None, scope='fc8')
        net = tf.squeeze(net, [1, 2])
        return net

def load_weights(input_image):
    # input_image = tf.placeholder(tf.float32, shape=[None, 96, 96, 3], name='input_image')
    with tf.variable_scope('vgg_16', reuse=tf.AUTO_REUSE):
        net = vgg16(input_image)

    variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)
    length = len(variables)
    parameters = []
    for i in range(6):
        parameters.append(variables[length - 6 + i])

    variable_restore_op = slim.assign_from_checkpoint_fn("pretrain_models/vgg_16.ckpt",variables[:length-2],ignore_missing_vars=True)
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        variable_restore_op(sess)
    print(parameters)
    return net, parameters

def create_placeholders(n_H0, n_W0, n_C0, n_y):
    X = tf.placeholder(tf.float32, shape=[None, 224, 224, 3])
    Y = tf.placeholder(tf.float32, [None, n_y])

    return X, Y

def compute_cost(Z3, Y):
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=Z3,labels=Y))
    return cost

def my_model(X_train, Y_train, X_test, Y_test, learning_rate=0.0001,num_epochs=30,minibatch_size=64,print_cost=True,isPlot=True):

    tf.reset_default_graph()
    tf.set_random_seed(1)
    seed = 3

    (m, n_H0, n_W0, n_C0) = X_train.shape
    n_y = Y_train.shape[1]
    costs = []
    X, Y = create_placeholders(n_H0,n_W0,n_C0,n_y)
    Z, parameters = load_weights(X)
    cost = compute_cost(Z, Y)
    #只训练var_list中的权重参数
    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost, var_list=parameters )
    print(parameters)
    print("begin training...")
    init = tf.global_variables_initializer()
    saver = tf.train.Saver()
    total_time = 0

    with tf.Session() as sess:
        sess.run(init)
        for epoch in range(1,num_epochs+1):
            #每一迭代的开始时间
            start_time = time.clock()
            #每一次迭代中所有batch的代价,即总的代价
            minibatches_cost = 0

            num_minibatches = int(m / minibatch_size)
            #将我们的数据随机打乱并根据batch_size随机分成若干个batch
            minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)
            for minibatch in minibatches:
                
                (minibatch_X, minibatch_Y) = minibatch
                _, temp_cost = sess.run([optimizer, cost], feed_dict={X: minibatch_X, Y:minibatch_Y})
                minibatches_cost += temp_cost/num_minibatches

            end_time = time.clock()
            total_time += (end_time - start_time)
            if print_cost:
                if epoch % 5 == 0:
                    print("当前是第 " + str(epoch) + " 代,成本值为:" + str(minibatches_cost) + " ; 每一个epoch花费时间:" + str(
                        end_time - start_time) + " 秒,5个epoch总的时间:" + str(total_time))
                    total_time = 0

            if epoch % 5 == 0:
                costs.append(minibatches_cost)

        saver.save(sess, "model_tf/my-model")
        if isPlot:
            plt.plot(np.squeeze(costs))
            plt.ylabel("cost")
            plt.xlabel("iterations (per tens)")
            plt.title("Learning rate =" + str(learning_rate))
            plt.show()

        predict_op = tf.argmax(Z, 1)
        corrent_prediction = tf.equal(predict_op, tf.argmax(Y, 1))

        accuracy = tf.reduce_mean(tf.cast(corrent_prediction, "float"))

        train_accuracy = accuracy.eval({X: X_train, Y: Y_train})
        test_accuracy = accuracy.eval({X: X_test, Y: Y_test})

        print("训练集准确度:" + str(train_accuracy))
        print("测试及准确度:" + str(test_accuracy))

    return (train_accuracy, test_accuracy)

from keras.datasets import mnist
(train_x, train_y), (test_x, test_y) = mnist.load_data()

train_x = train_x[:1000]
train_y = train_y[:1000]
test_x = test_x[:500]
test_y = test_y[:500]

train_x = np.array(train_x, dtype="uint8")
test_x = np.array(test_x, dtype="uint8")

#将灰度图中的单通道转为RGB多通道
train_x = [cv2.cvtColor(cv2.resize(x, (224, 224)), cv2.COLOR_GRAY2BGR) for x in train_x]
train_x = np.concatenate([arr[np.newaxis] for arr in train_x]).astype('float32')

test_x = [cv2.cvtColor(cv2.resize(x, (224, 224)), cv2.COLOR_GRAY2BGR) for x in test_x]
test_x = np.concatenate([arr[np.newaxis] for arr in test_x]).astype('float32')

train_y = train_y.reshape(len(train_y),1).astype(int)
test_y = test_y.reshape(len(test_y),1).astype(int)
train_y = convert_to_one_hot(train_y,10)
test_y = convert_to_one_hot(test_y, 10)

print("训练集:")
print(train_x.shape)
print(train_y.shape)
print("测试集:")
print(test_x.shape)
print(test_y.shape)

#训练模型
my_model(train_x, train_y, test_x, test_y)

(1)和3.1中基于tensorflow的实现,主要差别在于我们需要我们构建的vgg16网络结构是包含全连接层的,其中一点不同的是我们需要把输出层的神经元修改为我们需要的类别数。
(2)在使用slim.assign_from_checkpoint_fn恢复权重的时候我们恢复除输出层的其它层的权重,因为我们已经修改了输出层的神经元数目,因此指定恢复变量为variables[:length-2],因为最后一层包括weights和bias两个变量,所以是减2。
(3)关于冻结部分层的做法:我们只需要在指定优化器的时候,将我们需要训练的层的变量作为var_list参数传进去,而在本例子中我们需要训练的层是后面的全连接层,因此在load_weights函数中我们返回了全连接层的变量。

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost,var_list=parameters)

参考博客:
tf.contrib.slim简介
Tensorflow如何直接使用预训练模型(vgg16为例)
一文看懂迁移学习:怎样用预训练模型搞定深度学习?

迁移学习在Python中的应用 通过使用现有的预训练模型和相应的库和工具,我们可以快速构建适用于新任务的模型,并获得良好的性能。迁移学习是一种机器学习方法,通过将从一个任务中学到的知识应用于另一个相关任务中,可以加快新任务的学习速度,并提高其性能。在Python中,有许多强大的库和工具可用于实现迁移学习。迁移学习的核心思想是将一个预先训练好的模型的知识迁移到一个新的模型中。通过使用预训练模型和迁移学习技术,我们可以在相对较少的训练数据下构建高性能的机器学习模型。在训练过程中,我们可以选择解冻一些预训练模型的层,并根据需要微调它们的权重。 阅读详情

相关推荐

TensorFlow深度学习实战(10)——构建VGG模型实现图像分类

VGG 模型是一种经典的深度卷积神经网络 (Convolutional Neural Network, CNN) 架构,该模型以其简单而有效的设计而著名,在图像分类任务中取得了优异成绩。VGG 模型的核心特点是采用了深层的网络结构,其中大部分层由卷积层和池化层组成,且卷积操作使用了尺寸较小的 3 x 3 卷积核,这使得网络能够捕捉到丰富的图像特征。

盼小辉丶的博客 6662

Tensorflow迁移学习

使用别人已经训练好的模型来训练自己的任务。显示出验证数据中前3张图像的可视化结果。首先我们需要安装tensorflow。定义一个新模型,编译并训练这个模型。绘制训练过程中的准确率和损失曲线。绘制训练过程中的准确率和损失曲线。定义两个全连接层,用作模型预测。微调神经网络模型中的部分层。生成训练数据批量增强样本。生成验证数据批量增强样本。编译并训练一个网络模型。获取训练数据批次样本。

qq_52923100的博客 691

深度残差网络ResNet50模型详解与实战应用

ResNet50作为深度卷积神经网络中的里程碑式结构,通过引入残差学习框架,成功解决了网络深度增加带来的梯度消失与模型退化问题。其整体架构由1个初始卷积层、4个阶段的残差块堆叠(分别包含3、4、6、3个Bottleneck模块)以及全局平均池化层和全连接输出层构成,总计约2500万参数。该模型采用模块化设计,每阶段通过1×1卷积实现降维与升维,结合3×3卷积提取空间特征,在保持感受野的同时控制计算量。

weixin_42361478的博客 1198

详解常见的tensorflow,keras模型保存和加载

一定要看代码注释,这些模型格式可以互相转化,有兴趣自己查阅学习! Tensorflow 1、CheckPoint(.ckpt) :.ckpt方式保存模型,这种模型文件是依赖 TensorFlow 的,只能在其框架下使用(我很少使用这种,初学感觉文件好多,也不好理解) 参考TensorFlow模型保存和提取方法 保存: 利用tf.train.Saver类实现模型的保存和加载,直接上代码!!! import tensorflow as tf v1 = tf.Variable(tf.cons.

qq_26705249的博客 4286

基于Keras实现的声纹识别预训练模型

基于Keras实现的声纹识别预训练模型,源码地址:https://github.com/yeyupiaoling/VoiceprintRecognition-Keras

海康视觉相机驱动软件MVS参数配置全攻略(附接线图+避坑指南)

本文提供了海康视觉相机驱动软件MVS从硬件连接到软件参数配置的完整指南。详细解析了供电与通讯线缆的区分、PNP/NPN信号逻辑的接线避坑方法,并重点阐述了MVS软件中触发模式、网络IP配置、图像采集及光源控制等核心参数的设置技巧,旨在帮助用户快速完成相机调试,实现稳定高效的图像采集。

weixin_29204205的博客 400

Tensorflow2.0模型(官方文档)笔记:模型类的建立

Keras 有两个重要的概念: 模型(Model) 和 层(Layer) 。层将各种计算流程和变量进行了封装(例如基本的全连接层,CNN 的卷积层、池化层等),而模型则将各种层进行组织和连接,并封装成一个整体,描述了如何将输入数据通过各种层以及运算而得到输出。在需要模型调用的时候,使用 y_pred = model(X)的形式即可。 Keras 模型以类的形式呈现,我们可以通过继承 tf.kera...

XB_please的博客 811

Gazebo仿真平台模型搭建与修改

ROS里踩过的坑(一)Gazebo仿真平台模型搭建与修改文件讲解Models 文件World文件Launch文件模型编辑可视化编辑配置文件编辑模型展示如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出...

Redglass的博客 1万+

tensorflow 与keras 混用之坑

tensorflow 与keras 混用之坑在使用tensorflow与keras混用是model.save 是正常的但是在load_model的时候报错了在这里mark 一下原训练代码模型载入报错战斗种族解释 在使用tensorflow与keras混用是model.save 是正常的但是在load_model的时候报错了在这里mark 一下 其中错误为:TypeError: tuple indi...

u011557212的专栏 2万+

[苹果开发者账号]03 申请APPID、苹果开发者账号 常见问题整理

目录:问题持续更新问题一:提示:抱歉,您暂时不能注册问题二:Apple Developer Support提示:联系我们以继续流程 问题一:提示:抱歉,您暂时不能注册 申请苹果开发者账号,应该先注册AppleID,由于很多都是申请的公司使用的苹果开发者账号。一般操作申请动作的人,可能是新手操作,也可能图方便,有些信息会随便填写。 有些人会把姓名填写为,公司的产品、简称、缩写等等。这是不对的。 还有出生日期也会随便乱填。生日如果填写的不对,会被苹果限制使用一些功能的(苹果给的提示不是太明确)。 当生日填写的

专注于技术开发、项目管理 1万+

静态分析工具COBOT与Testbed对比

Testbed为规则检查工具的代表,市场占有量非常大,但随着时间的推移,大家从规则匹配转向了用静态分析工具检查Bug,所以规则检查型工具占有量比开始时候已经减少,但仍有一些比较落后的单位还在继续采购此类工具。3、通过对开源工程的测试,进行误漏报率的对比,发现COBOT(库博)的误漏报率相比Testbed较低,因COBOT主打国内市场,在众多军工单位进行大量试用及使用,吸取了众多单位的意见和建议,更加符合国内军工单位的使用习惯及测试要求。4、此外库博在功能上还可以进行计划任务,检测队列,检测并发的功能支持。

chengoodflower的博客 2058

Classification Models 项目教程

`classification_models` 是一个用于在 Keras 和 TensorFlow Keras 中使用预训练的 ImageNet 分类模型的库。该库提供了多种流行的深度学习模型架构,如 VGG、ResNet、ResNeXt、SE-ResNet、SE-ResNeXt、DenseNet、Inception ResNet V2、Inception V3、Xception、NASNet、M

gitblog_00864的博客 406

Fluent DPM模型保姆级教程:三通管颗粒流动模拟,从网格导入到轨迹图生成

本文提供Fluent DPM模型在三通管颗粒流动模拟中的保姆级教程,涵盖从网格导入到轨迹图生成的全流程。通过详细步骤和参数设置,帮助用户掌握DPM模型在颗粒流动模拟中的关键技巧,适用于化工、能源等领域的工程应用。

weixin_30615767的博客 579

使用 `vit-keras` 进行图像识别

使用 vit-keras 进行图像识别 项目介绍 vit-keras 是一个基于 Keras 的库,用于实现 Vision Transformer(ViT)模型。Vision Transformer 是一种新型的深度学习架构,它将 Transformer 模型应用于图像识别任务,通过将图像分割成小块(patches)并将其线性嵌入,来处理图像数据。vit-keras 项目使得在 Keras 中使用...

gitblog_00432的博客 497

单反相机物镜设计[DG-10]

REAR(要打在像面,操作数要找像面对应位置15):以透镜单位表示的真实光线径向坐标,波长由Wave定义,参见“Hx、Hy、Px和Py”。最小玻璃厚度最小不能小于semi-dia的1/10,要根据layout看有没有过厚过薄,反复调节。PROD:两个操作数的乘积(操作#1 X操作#2)。3x4就是57.3x0.41=23.5。拦光一般在第一面和最后一面操作,减少边缘无用光线。光阑面与镜面贴近,要调距离,同时设置光阑像差。后截距是指从镜头后表面到焦点的距离。CONS:弧度转为角度。镜头相互嵌入,有错误。

weixin_72050316的博客 600

51单片机+L298驱动步进电机+L297测速+LCD1602显示+按键调试+Proteus仿真

51单片机+L298驱动步进电机+L297测速+LCD1602显示+按键调试+Proteus仿真 *Proteus仿真 L298N是双H桥式驱动器。 L297是步进电机控制集成芯片(包括环形分配器),可产生四相驱动信号,应用于微处理机控制两相双极性和四相单极性步进电机。电动机可由半阶梯、正常和斩波驱动模式驱动,同时设于晶片内的PWM斩波线路容许以开关形式控制线路的电流。此器件只需要时钟、方向和模式输入信号。相位是由内部产生的,因此可减轻微处理机和程序设计的负担。 实例代码 /************

perseverance51博客 4585

Python实战:用VGG19预训练模型快速实现图像分类(附完整代码)

本文详细介绍了如何使用Python和VGG19预训练模型快速构建高效的图像分类系统。通过环境配置、模型加载、图像预处理、自定义分类器实现以及模型推理等步骤,帮助开发者掌握迁移学习的关键技术。文章还提供了完整的代码示例和性能优化技巧,适用于计算机视觉领域的实际应用开发。

weixin_29093017的博客 236

后仿真中《SDF反标必懂连载篇》之 <INTERCONNECT/IOPATH> 到底反标电路路径是哪里

对于SDF INTERCONNECT ENTRY 描述,我们在之前的文章有详解。读万卷书,行万里路。实践很重要。今天,搞一下SDF INTERCONNECT / IOPATH 延迟数据信息,究竟反标的是哪一路径延时?究竟在电路上一段段如何表现出延迟现象的呢?

那么菜的博客 2135

人工智能|深度学习——基于Xception算法模型实现一个图像分类识别系统

在计算机视觉领域,图像识别是一个非常重要的任务,其应用涵盖了人脸识别、物体检测、场景理解等众多领域。随着深度学习技术的发展,深度卷积神经网络(Convolutional Neural Networks,简称CNN)在图像识别任务上取得了巨大成功,其中Xception算法作为一种改进型CNN,被广泛应用于图像分类和特征提取任务。本章节将重点介绍Xception算法的背景、原理及其在图像识别系统中的应用。

也许有一天我们再相逢 睁开眼睛看清楚 我才是英雄! 2389

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

EfficientNet迁移学习完全指南:在自定义数据集上实现快速部署

EfficientNet是由Google提出的高效卷积神经网络模型,通过复合缩放方法实现了精度和效率的最佳平衡。本指南将带您了解如何利用EfficientNet进行迁移学习,在自定义数据集上快速构建高性能图像分类模型,即使是深度学习新手也能轻松掌握。 ## 为什么选择EfficientNet进行迁移学习? EfficientNet系列模型(B0到B7以及L2)通过网络深度、宽度和分辨率的平衡缩

gitblog_01005的博客 500

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

2026年AI开发趋势入门必看:TensorFlow开源模型+弹性GPU部署

本文介绍了如何在星图GPU平台上自动化部署TensorFlow-v2.15镜像,快速构建AI开发环境。该平台提供开箱即用的环境与弹性算力,用户可基于此镜像轻松加载预训练模型,实现图像分类等典型应用,显著降低AI入门门槛并提升开发效率。

weixin_28999139的博客 923

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

VGG16迁移学习实现猫狗二分类:从原理到实战

深度学习中的迁移学习是一种将预训练模型学到的通用特征复用到新任务的高效策略。以VGG16为代表的卷积神经网络在ImageNet上学习了丰富的边缘、纹理等底层特征,具有极强的泛化能力。通过冻结预训练网络的卷积层并微调新增分类头,即便在少量标注数据上也能达到高精度识别效果。该方法广泛应用于猫狗识别、医学影像分析、工业质检等图像分类场景。本文以猫狗二分类任务为切入点,详细讲解VGG16预训练模型的加载与改造、两阶段训练策略、关键调参技巧以及常见问题排查,帮助读者快速掌握迁移学习在图像分类中的工程落地方法。

weixin_29045001的博客 261

使用TensorFlow构建和优化卷积神经网络实践指南与性能提升技巧

当模型结构变得复杂,例如需要多输入、多输出或层之间存在非顺序连接(如残差连接)时,Keras Functional API是比Sequential API更强大的选择。Functional API允许定义复杂的拓扑结构,为构建诸如ResNet、Inception等现代CNN架构提供了灵活性。使用Functional API,每一层的调用操作都返回一个张量,并且可以将后续层作为函数来调用这个张量,从而定义任意的前向传播图。

csdn_lizhenwen的博客 760

【Python练习】074. 编写一个函数,实现简单的图像识别功能

这篇文章介绍了如何使用Python和TensorFlow实现简单的图像识别功能。主要内容包括: 安装TensorFlow依赖库 使用MNIST数据集构建卷积神经网络模型 数据预处理和模型训练流程 模型评估方法,示例准确率达98.24% 扩展功能建议:数据增强、预训练模型、模型保存等 其他实现方法:预训练模型ResNet50、传统特征提取+SVM、轻量级框架TFLite等 文章提供了完整的代码示例和详细说明,适用于初学者快速实现基础图像识别功能,并为进一步优化提供了方向。

视睿 499

VGG16迁移学习猫狗分类实战:从特征提取到微调全流程解析

迁移学习是深度学习中解决小数据集训练难题的核心方法,其原理在于将预训练模型在大型数据集(如ImageNet)上学到的通用视觉特征迁移到新任务中,从而避免从零训练带来的算力浪费与过拟合风险。VGG16作为经典卷积神经网络,其层次化特征提取能力使其成为迁移学习的理想底座。在实际工程中,通过冻结卷积基进行特征提取,再解冻部分层进行微调,可显著提升猫狗分类等图像识别任务的准确率。这一技术路线不仅适用于入门级的猫狗分类项目,还可泛化至工业质检、医学影像等真实场景,帮助开发者快速构建高性能分类模型。本文以VGG16与猫

weixin_29039773的博客 300

实战指南:从零开始用Mask R-CNN训练自定义数据集(附完整代码)

本文提供了一份从零开始使用Mask R-CNN训练自定义数据集的完整实战指南。详细介绍了从环境搭建、使用labelme进行数据标注、编写自定义训练脚本,到加载预训练权重、启动训练并利用TensorBoard监控训练过程的每一步。指南包含核心代码解析与避坑经验,旨在帮助读者高效完成模型训练与部署。

chair的专栏 406
上一篇: 基于tensorflow的手写数字体识别
下一篇: 在Google Colab上面进行深度学习的模型训练
Donreen
博客等级 码龄9年 64粉丝 35原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值