分析Keras使用方法

[TOC]

分析基于Keras构建模型

参考代码1-coral introduction from youtube

youtube video

keras guides

colab环境搭建模型

数据集的建立和下载

kaggle -里面有大量的数据集可提供免费下载

安装required library

1
2
3
4
5
import tensorflow as tf

import os
import numpy as np
import matplotlib.pyplot as plt

安装API

1
!pip install kaggle

使用Kaggle

在colab使用kaggle需要在官网下载一个key, 点击Creat New API token,自动下载一个kaggle.json文件,然后导入colab。

使用的数据集是kaggle里的fruit360

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#在colab上连接google云盘,因为我的kaggle.json文件放到我的google云盘里了.
from google.colab import drive
drive.mount('/content/drive')

#本地创建一个.kaggle文件夹
! mkdir ~/.kaggle
#复制colab的kaggle.json文件到新创建的文件夹
!cp /content/drive/MyDrive/kaggle/kaggle.json ~/.kaggle/kaggle.json
#现在可以下载数据集了,这个是水果数据集,可以在kaggle里copy api command
!kaggle datasets download -d moltean/fruits
#解压数据集
!unzip '/content/fruits.zip'
#映射对象并分配对象,将名字修改成username,密码为key
import os
os.environ['KAGGLE_USERNAME'] = "<username>"
os.environ['KAGGLE_KEY'] = "<key>"

使用数据集

不能使用MobileNetV1/2/3来训练cifar100,因为分辨率不同.

使用keras的库来数据预处理 图片预处理

这个数据集有131个分类,也就是有131个标签,每个标签代表一个水果或蔬菜。

训练集有67692 images,测试集有22688 images。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#IMAGE_SIZE是100*100分辨率,因为下载的图片就是100*100的分辨率,当然也可以是其他分辨率图像,因为这是预处理。
#BATCH_SIZE是数据集的批次,生成64批。
IMAGE_SIZE = 96
BATCH_SIZE = 64

#rescale是一个值,在任何其他处理之前,我们将把数据乘以这个值。我们的原始图像由0-255的RGB系数组成,但这样的值对我们的模型来说太高了,无法处理(考虑到典型的学习率),所以我们的目标是用1/255的比例来代替0和1之间的值。
#validation_split用于随机缩放照片
datagen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1./255,
validation_split=0.2)
#train_generator是训练生成器,调用flow_from_directory()来创建,它们直接从各自文件夹中的 jpg 生成批量图像数据(及其标签)。
#训练的数据不是直接用的jpg照片,而是压缩后的照片,所以我们需要数据生成器。
train_generator = datagen.flow_from_directory(
'/content/fruits-360_dataset/fruits-360/Training',
target_size=(IMAGE_SIZE, IMAGE_SIZE),
batch_size=BATCH_SIZE)
#val_gennerator生成可以验证模型的数据集。
val_generator = datagen.flow_from_directory(
'/content/fruits-360_dataset/fruits-360/Test',
target_size=(IMAGE_SIZE, IMAGE_SIZE),
batch_size=BATCH_SIZE)
1
2
3
#在每次迭代中,这些生成器通过从磁盘上读取图像并将其处理为适当的张量大小(100 x 100)来提供一批图像。输出是一个(图像,标签)的元组。例如,你可以看到这里的shapes。
image_batch, label_batch = next(val_generator)
image_batch.shape, label_batch.shape

保存数据集里的label,并放在txt里,因为是yolo模型

.key sorted open

.class_indicaes-它来自flow_from_directory,可直接引用。

1
2
3
4
5
6
7
8
9
10
#从train_generator中使用class_indices来提取label,class_indices是来自keras库的。
print (train_generator.class_indices)
#该join()方法获取一个可迭代对象中的所有项目并将它们连接成一个字符串,python函数.
#该sorted()函数返回指定可迭代对象的排序列表,python函数。
#train_generator.class_indices.keys,该keys()方法返回一个视图对象。视图对象包含字典的key,作为列表。
labels = '\n'.join(sorted(train_generator.class_indices.keys()))

#创造新文件,使用open函数.
with open('fruit_labels.txt', 'w') as f:
f.write(labels)

可以在terminal直接wc -lc fruit_labels.txt,能显示多少行字和字数。

1
2
#显示文件内容,终端也能用。
!cat fruit_labels.txt

构建模型

现在我们将创建一个模型,能够在最后一个全连接层上进行迁移学习。

我们将从Keras的MobileNet V2开始作为基础模型,它已经用ImageNet数据集进行了预训练(训练后可识别1000个类别)。这为我们提供了一个非常好的图像分类特征提取器。

创建底层(Base_model)

在实例化MobileNetV2模型时,我们指定include_top=False参数,以便在加载网络时不把分类层放在顶部。然后我们设置trainable false来冻结基础模型中的所有权重。这就有效地将模型转换成了一个特征提取器,因为当我们开始训练分类头时,所有预训练的权重和偏置都保留在低层。

MobileNetV2

Transfer Learning -冻结底层

input_shape :可选的形状元组,只有在include_top为False时才被指定(否则输入形状必须是(224, 224, 3)(用channel_last数据格式)或(3, 224, 224)(用channel_first数据格式)。它应该正好有3个输入通道,并且宽度和高度不应小于32。例如,(200, 200, 3)将是一个有效值。默认为无。如果提供了input_tensor,input_shape将被忽略.但是官方还有别的规定,宽度和高度必须在96, 128, 160, 192, 224中任意选择其中一个,不能自定义。

MobileNetV3 only 224,224

Weights: none(随机初始化),’imagenet’(在ImageNet上进行预训练),或要加载的权重文件的路径之一。默认为imagenet。

1
2
3
4
5
6
7
8
IMG_SHAPE = (IMAGE_SIZE, IMAGE_SIZE, 3)

# Create the base model from the pre-trained MobileNet V2
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet')
#Then, freeze the base model.冻结最底层
base_model.trainable = False

添加分类头

Add a classification head

tf.keras.Sequential class

Conv2D Dropout GlobalAveragePooling2D Dense

现在我们创建一个新的序列模型,并将冻结的MobileNet模型作为图的基础,并附加新的分类层,这样我们就可以将最终的输出维度设置为与我们的数据集中的类别数量相匹配(131种水果和蔬菜)。

在网站学习CNN

1
2
3
4
5
6
7
model = tf.keras.Sequential([
base_model,
tf.keras.layers.Conv2D(filters=32, kernel_size=3, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(units=len(labels.split('\n')), activation='softmax')
])

Configure the model

Although this method is called compile(), it’s basically a configuration step that’s required before we can start training.

虽然这个方法被称为compile(),但它基本上是一个配置步骤,在我们开始训练之前需要进行配置。

model training API metric 指标 losses

1
2
3
model.compile(optimizer='adam', 
loss='categorical_crossentropy',
metrics=['accuracy'])

You can see a string summary of the final network with the summary() method:

你可以用summary()方法看到最终网络的字符串摘要:

the model class

1
model.summary()

And because the majority of the model graph is frozen in the base model, weights from only the last convolution and dense layers are trainable:

由于大部分的模型图被冻结在基础模型中,只有最后的卷积层和密集层的权重是可训练的。

The base Layer class -the trainable_weights

format function in python len

1
print('Number of trainable weights = {}'.format(len(model.trainable_weights)))

训练模型

Now we can train the model using data provided by the train_generator and val_generator that we created at the beginning.

现在我们可以使用一开始创建的train_generatorval_generator所提供的数据来训练模型。

model training len

1
2
3
4
5
history = model.fit(train_generator,
steps_per_epoch=len(train_generator),
epochs=10,
validation_data=val_generator,
validation_steps=len(val_generator))

查看学习曲线

history.history can search in model

matplotlib.figure matplotlib.subplot … which all can reaserch inmatplotlib reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#acc为精准度accuracy.
acc = history.history['accuracy']
#验证集的精准度.
val_acc = history.history['val_accuracy']
#损失
loss = history.history['loss']
#验证集损失
val_loss = history.history['val_loss']


plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()

微调模型

So far, we’ve only trained the classification layers—the weights of the pre-trained network were not changed.

到目前为止,我们只训练了分类层–预训练网络的权重没有改变。

One way we can increase the accuracy is to train (or “fine-tune”) more layers from the pre-trained model. That is, we’ll un-freeze some layers from the base model and adjust those weights (which were originally trained with 1,000 ImageNet classes) so they’re better tuned for features found in our fruits dataset.

我们可以提高准确率的一个方法是训练(或 “微调”)更多预训练模型的层。也就是说,我们将从基础模型中解冻一些层,并调整这些权重(这些权重最初是用1000个ImageNet类来训练的),以便它们能更好地适应我们的水果数据集中的特征。

解冻更多的层

So instead of freezing the entire base model, we’ll freeze individual layers.

因此,我们不是冻结整个基础模型,而是冻结个别图层.

First, let’s see how many layers are in the base model:

首先,让我们看看基本模型中有多少层。

keras layer api

1
print("Number of layers in the base model: ", len(base_model.layers))

Let’s try freezing just the bottom 100 layers.

让我们试着只冻结底部的100层。

trainable api

1
2
3
4
5
6
base_model.trainable = True
fine_tune_at = 100

# Freeze all the layers before the `fine_tune_at` layer
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False

Compile model

Now configure the model again, but this time with a lower learning rate (the default is 0.001).

现在再次配置该模型,但这次使用较低的学习率(默认为0.001)。

model training API metric 指标 losses

1
2
3
model.compile(optimizer=tf.keras.optimizers.Adam(1e-5),
loss='categorical_crossentropy',
metrics=['accuracy'])
1
model.summary()
1
print('Number of trainable weights = {}'.format(len(model.trainable_weights)))

继续训练

1
2
3
4
5
history_fine = model.fit(train_generator,
steps_per_epoch=len(train_generator),
epochs=5,
validation_data=val_generator,
validation_steps=len(val_generator))

查看学习曲线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
acc = history_fine.history['accuracy']
val_acc = history_fine.history['val_accuracy']

loss = history_fine.history['loss']
val_loss = history_fine.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()

转化TFLite模型

Ordinarily, creating a TensorFlow Lite model is just a few lines of code with TFLiteConverter. For example, this creates a basic (un-quantized) TensorFlow Lite model:

通常情况下,创建一个TensorFlow Lite模型只需要用TFLiteConverter写几行代码。例如,这将创建一个基本的(未量化的)TensorFlow Lite模型。

1
2
3
4
5
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()

with open('mobilenet_v2_1.0_224.tflite', 'wb') as f:
f.write(tflite_model)

However, this .tflite file still uses floating-point values for the parameter data, and we need to fully quantize the model to int8 format.

然而,这个.tflite文件仍然使用浮点值作为参数数据,我们需要将模型完全量化为int8格式。

To fully quantize the model, we need to perform post-training quantization with a representative dataset, which requires a few more arguments for the TFLiteConverter, and a function that builds a dataset that’s representative of the training dataset.

为了完全量化模型,我们需要用一个有代表性的数据集进行训练后量化,这需要为TFLiteConverter增加一些参数,以及建立一个能代表训练数据集的数据集的函数。

So let’s convert the model again with post-training quantization:

因此,让我们再次用训练后量化来转换模型。

def 创造函数

tf.data api next iter tf.io api tf.image.resize

tf.case -里面饱和了各种可转化的数据类型(dtype)

tf.expand_dims -会解释为什么是axis=0

yield 的解释 -大概就是生成器通过yield输出一次,如果有循环则返回生成器继续输出,它没有记忆,算完一次忘一次。

tf.lite.TFLiteConverter api

tf.lite.optimize -从转化到量化到过程都有,完全照搬的直接搜int8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# A generator that provides a representative dataset
def representative_data_gen():
dataset_list = tf.data.Dataset.list_files('/content/fruits-360_dataset/fruits-360/*/*.jpg')
for i in range(100):
image = next(iter(dataset_list))
image = tf.io.read_file(image)
image = tf.io.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [IMAGE_SIZE, IMAGE_SIZE])
image = tf.cast(image / 255., tf.float32)
image = tf.expand_dims(image, 0)
yield [image]

converter = tf.lite.TFLiteConverter.from_keras_model(model)
# This enables quantization
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# This sets the representative dataset for quantization
converter.representative_dataset = representative_data_gen
# This ensures that if any ops can't be quantized, the converter throws an error
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
# For full integer quantization, though supported types defaults to int8 only, we explicitly declare it for clarity.
converter.target_spec.supported_types = [tf.int8]
# These set the input and output tensors to uint8 (added in r2.3)
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
tflite_model = converter.convert()
#保存模型
with open('mobilenet_v2_1.0_224_quant.tflite', 'wb') as f:
f.write(tflite_model)

比较精准度

So now we have a fully quantized TensorFlow Lite model. To be sure the conversion went well, let’s evaluate both the raw model and the TensorFlow Lite model.

所以现在我们有一个完全量化的TensorFlow Lite模型。为了确保转换顺利,让我们同时评估原始模型和TensorFlow Lite模型。

First check the accuracy of the raw model:

首先检查原始模型的准确性。

numpy api

metric

1
2
3
4
5
6
7
8
9
10
batch_images, batch_labels = next(val_generator)

logits = model(batch_images)
prediction = np.argmax(logits, axis=1)
truth = np.argmax(batch_labels, axis=1)

keras_accuracy = tf.keras.metrics.Accuracy()
keras_accuracy(prediction, truth)

print("Raw model accuracy: {:.3%}".format(keras_accuracy.result()))

Now let’s check the accuracy of the .tflite file, using the same dataset.

现在让我们检查一下.tflite文件的准确性,使用相同的数据集。

However, there’s no convenient API to evaluate the accuracy of a TensorFlow Lite model, so this code runs several inferences and compares the predictions against ground truth:

然而,没有方便的API来评估TensorFlow Lite模型的准确性,所以这段代码运行了几个推断,并将预测与地面实况进行比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def set_input_tensor(interpreter, input):
input_details = interpreter.get_input_details()[0]
tensor_index = input_details['index']
input_tensor = interpreter.tensor(tensor_index)()[0]
# Inputs for the TFLite model must be uint8, so we quantize our input data.
# NOTE: This step is necessary only because we're receiving input data from
# ImageDataGenerator, which rescaled all image data to float [0,1]. When using
# bitmap inputs, they're already uint8 [0,255] so this can be replaced with:
# input_tensor[:, :] = input
scale, zero_point = input_details['quantization']
input_tensor[:, :] = np.uint8(input / scale + zero_point)

def classify_image(interpreter, input):
set_input_tensor(interpreter, input)
interpreter.invoke()
output_details = interpreter.get_output_details()[0]
output = interpreter.get_tensor(output_details['index'])
# Outputs from the TFLite model are uint8, so we dequantize the results:
scale, zero_point = output_details['quantization']
output = scale * (output - zero_point)
top_1 = np.argmax(output)
return top_1

interpreter = tf.lite.Interpreter('mobilenet_v2_1.0_224_quant.tflite')
interpreter.allocate_tensors()

# Collect all inference predictions in a list
batch_prediction = []
batch_truth = np.argmax(batch_labels, axis=1)

for i in range(len(batch_images)):
prediction = classify_image(interpreter, batch_images[i])
batch_prediction.append(prediction)

# Compare all predictions to the ground truth
tflite_accuracy = tf.keras.metrics.Accuracy()
tflite_accuracy(batch_prediction, batch_truth)
print("Quant TF Lite accuracy: {:.3%}".format(tflite_accuracy.result()))

You might see some, but hopefully not very much accuracy drop between the raw model and the TensorFlow Lite model. But again, these results are not suitable for production deployment.

你可能会看到一些,但希望在原始模型和TensorFlow Lite模型之间不会有很大的精度下降。但同样,这些结果并不适合用于生产部署。

Compile for the Edge TPU

Finally, we’re ready to compile the model for the Edge TPU.

最后,我们准备为Edge TPU编译模型。

First download the Edge TPU Compiler:

首先下载Edge TPU Compiler

1
2
3
4
5
6
7
! curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

! echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list

! sudo apt-get update

! sudo apt-get install edgetpu-compiler

Then compile the model:

1
! edgetpu_compiler mobilenet_v2_1.0_224_quant.tflite

That’s it.

The compiled model uses the same filename but with “_edgetpu” appended at the end.

Download the model

1
2
3
4
from google.colab import files

files.download('mobilenet_v2_1.0_224_quant_edgetpu.tflite')
files.download('fruit_labels.txt')

Run the model on the Edge TPU

You can now run the model on your Coral device with acceleration on the Edge TPU.

To get started, try using your .tflite model with this code for image classification with the TensorFlow Lite API.

Just follow the instructions on that page to set up your device, copy the mobilenet_v2_1.0_224_quant_edgetpu.tflite and flower_labels.txt files to your Coral Dev Board or device with a Coral Accelerator, and pass it a flower photo like this:

1
2
3
4
python3 classify_image.py \
--model mobilenet_v2_1.0_224_quant_edgetpu.tflite \
--labels flower_labels.txt \
--input flower.jpg

Check out more examples for running inference at coral.ai/examples.

  • Copyrights © 2022-2024 Jessy Huang
  • Visitors: | Views:

请我喝杯咖啡吧~