import tensorflow as tf
import os
import matplotlib.pyplot as plt
from time import time
# 定义标签字典(根据实际类别修改)
label_dict = {
'electrodrill': 0,
'headphones': 1,
'keyboard': 2,
'mobile_phone': 3,
'monitor': 4,
'mouse': 5,
'multimeter': 6,
'number': 7,
'oscillograph': 8,
'pliers': 9,
'printer': 10,
'screwdriver': 11,
'soldering_iron': 12,
'speaker': 13,
'tape_measure': 14,
'wrench': 15
}
def data_load(data_dir, test_data_dir, img_height, img_width, batch_size):
def process_image(image_path):
image = tf.io.read_file(image_path)
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [img_height, img_width])
image = (image / 127.5) - 1.0 # MobileNet标准化
return image
def parse_path(path):
# 转换为numpy字符串处理路径
path_str = path.numpy().decode('utf-8')
# 获取类别文件夹名
class_name = tf.strings.split(path_str, os.path.sep)[-2].numpy().decode('utf-8')
# 从预定义的字典获取标签索引
label_idx = label_dict.get(class_name, -1) # -1表示未知类别
if label_idx == -1:
raise ValueError(f"未知类别: {class_name}")
return process_image(path), label_idx
def map_fn(path):
# 使用py_function包装Python逻辑
image, label = tf.py_function(
func=parse_path,
inp=[path],
Tout=[tf.float32, tf.int32]
)
# 设置明确的Tensor形状
image.set_shape([img_height, img_width, 3])
label.set_shape([])
# 将标签转换为one-hot编码
label = tf.one_hot(label, depth=len(label_dict))
return image, label
def load_dataset(directory):
# 获取所有图片路径
dataset = tf.data.Dataset.list_files(directory + '/*/*.jpg', shuffle=True)
# 应用处理函数
dataset = dataset.map(
map_fn,
num_parallel_calls=tf.data.experimental.AUTOTUNE
)
return dataset
# 加载数据集
train_ds = load_dataset(data_dir)
val_ds = load_dataset(test_data_dir)
# 批处理和预取
train_ds = train_ds.batch(batch_size).prefetch(tf.data.experimental.AUTOTUNE)
val_ds = val_ds.batch(batch_size).prefetch(tf.data.experimental.AUTOTUNE)
# 验证数据预处理是否正确
for images, labels in train_ds.take(1):
# 检查图像标准化是否正确
min_value = tf.reduce_min(images)
max_value = tf.reduce_max(images)
print(f"图像标准化检查: 最小值 = {min_value.numpy()}, 最大值 = {max_value.numpy()}")
assert min_value >= -1 and max_value <= 1, "图像标准化错误,范围应为[-1, 1]"
# 检查标签是否为one-hot编码且正确
print("标签示例:", labels[0].numpy()) # 应为one-hot如[0,0,1,...,0]
assert tf.reduce_sum(labels[0]).numpy() == 1, "标签应该是one-hot编码,其中只有一个值为1,其余为0"
return train_ds, val_ds
def model_load(IMG_SHAPE=(224, 224, 3), class_num=16, learning_rate=0.01): # 添加learning_rate参数
base_model = tf.keras.applications.MobileNetV2(
input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet'
)
base_model.trainable = False
model = tf.keras.Sequential([
base_model,
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(class_num, activation='softmax')
])
# 显式设置学习率的优化器
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
model.compile(
optimizer=optimizer, # 使用自定义优化器
loss='categorical_crossentropy',
metrics=['accuracy']
)
model.summary()
return model
def show_loss_acc(history):
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.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.savefig('results/results_mobilenet.png', dpi=100)
def train(epochs):
begin_time = time()
# 创建必要目录
os.makedirs("models", exist_ok=True)
os.makedirs("results", exist_ok=True)
try:
print("加载数据集中...")
train_ds, val_ds = data_load(
"C:/Users/dll20/Desktop/vegetables_tf2.3-master/new_data/train",
"C:/Users/dll20/Desktop/vegetables_tf2.3-master/new_data/val",
224, 224, 16
)
# 验证数据加载
for images, labels in train_ds.take(1):
print(f"图像形状: {images.shape}, 标签形状: {labels.shape}")
print(f"标签示例: {labels[0].numpy()}")
print("类别数量:", len(label_dict))
print("类别映射:", label_dict)
model = model_load(class_num=len(label_dict))
print("开始训练...")
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=epochs,
verbose=1
)
model.save("models/mobilenet_engineer.h5")
show_loss_acc(history)
except Exception as e:
print(f"训练出错: {str(e)}")
import traceback
traceback.print_exc()
finally:
print(f"总耗时: {time() - begin_time:.2f}秒")
if __name__ == '__main__':
# 配置TensorFlow
tf.config.run_functions_eagerly(False)
physical_devices = tf.config.list_physical_devices('GPU')
if physical_devices:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
图像标准化检查: 最小值 = -1.0, 最大值 = 1.0
标签示例: [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
图像形状: (16, 224, 224, 3), 标签形状: (16, 16)
标签示例: [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
类别数量: 16
类别映射: {'electrodrill': 0, 'headphones': 1, 'keyboard': 2, 'mobile_phone': 3, 'monitor': 4, 'mouse': 5, 'multimeter': 6, 'number': 7, 'oscillograph': 8, 'pliers': 9, 'printer': 10, 'screwdriver': 11, 'soldering_iron': 12, 'speaker': 13, 'tape_measure': 14, 'wrench': 15}
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
mobilenetv2_1.00_224 (Functi (None, 7, 7, 1280) 2257984
_________________________________________________________________
global_average_pooling2d (Gl (None, 1280) 0
_________________________________________________________________
dense (Dense) (None, 16) 20496
=================================================================
Total params: 2,278,480
Trainable params: 20,496
Non-trainable params: 2,257,984
_________________________________________________________________
开始训练...
Epoch 1/100
2025-05-17 20:14:57.943383: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library cublas64_10.dll
2025-05-17 20:16:05.881342: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library cudnn64_7.dll
2025-05-17 20:19:28.437448: W tensorflow/stream_executor/gpu/redzone_allocator.cc:314] Internal: Invoking GPU asm compilation is supported on Cuda non-Windows platforms only
Relying on driver to perform ptx compilation.
Modify $PATH to customize ptxas location.
This message will be only logged once.
1024/1024 [==============================] - 53s 52ms/step - loss: 9.9016 - accuracy: 0.0606 - val_loss: 9.3069 - val_accuracy: 0.0701
Epoch 2/100
1024/1024 [==============================] - 77s 75ms/step - loss: 10.5672 - accuracy: 0.0642 - val_loss: 10.8782 - val_accuracy: 0.0718
Epoch 3/100
1024/1024 [==============================] - 80s 78ms/step - loss: 10.6035 - accuracy: 0.0639 - val_loss: 10.8998 - val_accuracy: 0.0658
Epoch 4/100
1024/1024 [==============================] - 78s 76ms/step - loss: 10.4597 - accuracy: 0.0658 - val_loss: 9.5053 - val_accuracy: 0.0581
Epoch 5/100
1024/1024 [==============================] - 77s 75ms/step - loss: 10.1673 - accuracy: 0.0596 - val_loss: 12.2643 - val_accuracy: 0.0620
Epoch 6/100
1024/1024 [==============================] - 81s 79ms/step - loss: 10.1886 - accuracy: 0.0628 - val_loss: 9.2048 - val_accuracy: 0.0641
Epoch 7/100
1024/1024 [==============================] - 78s 76ms/step - loss: 10.2992 - accuracy: 0.0630 - val_loss: 10.0681 - val_accuracy: 0.0658
Epoch 8/100
1024/1024 [==============================] - 65s 63ms/step - loss: 10.2812 - accuracy: 0.0665 - val_loss: 12.2382 - val_accuracy: 0.0645
Epoch 9/100
1024/1024 [==============================] - 76s 74ms/step - loss: 11.4436 - accuracy: 0.0637 - val_loss: 9.5845 - val_accuracy: 0.0697
Epoch 10/100
1024/1024 [==============================] - 55s 54ms/step - loss: 10.2822 - accuracy: 0.0664 - val_loss: 9.9871 - val_accuracy: 0.0632
Epoch 11/100
1024/1024 [==============================] - 56s 55ms/step - loss: 10.9518 - accuracy: 0.0647 - val_loss: 12.8353 - val_accuracy: 0.0603
Epoch 12/100
1024/1024 [==============================] - 57s 55ms/step - loss: 10.7480 - accuracy: 0.0646 - val_loss: 10.8068 - val_accuracy: 0.0607
Epoch 13/100
1024/1024 [==============================] - 56s 54ms/step - loss: 10.3040 - accuracy: 0.0618 - val_loss: 11.6900 - val_accuracy: 0.0628
Epoch 14/100
1024/1024 [==============================] - 54s 52ms/step - loss: 10.5912 - accuracy: 0.0630 - val_loss: 14.3563 - val_accuracy: 0.0778
Epoch 15/100
1024/1024 [==============================] - 53s 52ms/step - loss: 10.7772 - accuracy: 0.0635 - val_loss: 11.0138 - val_accuracy: 0.0641
Epoch 16/100
1024/1024 [==============================] - 53s 52ms/step - loss: 10.1329 - accuracy: 0.0651 - val_loss: 11.0438 - val_accuracy: 0.0632
Epoch 17/100
1024/1024 [==============================] - 54s 52ms/step - loss: 10.4157 - accuracy: 0.0617 - val_loss: 11.4240 - val_accuracy: 0.0662
Epoch 18/100
1024/1024 [==============================] - 57s 55ms/step - loss: 10.4042 - accuracy: 0.0635 - val_loss: 11.6729 - val_accuracy: 0.0624
train(epochs=100) 我上述代码运行输出 一共16个类 正确率一直这么低 基本没变化 感觉就是没用上这个模型的感觉 不是微调的问题 我的目的是图像分类出16个种类 帮我检查这个代码 帮我找找原因