Mac m1安装Tensorflow-metal导致模型准确率降低

如题,在M1 Mac上使用tensorflow跑vgg网络,正常时准确率不断上升,经过5个epoch后为0.7315,但是速度很慢。在安装了tensorflow-metal进行硬件加速后,时间大幅缩短,但是准确率一直维持在0.1左右,几乎与乱选准确率相同。
代码为北大tensorflow笔记公开课CNN部分,数据集为cifar10,具体代码如下:

import tensorflow as tf
import os
import numpy as np
from matplotlib import pyplot as plt
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Dropout, Flatten, Dense
from tensorflow.keras import Model

np.set_printoptions(threshold=np.inf)

cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0


class VGG16(Model):
    def __init__(self):
        super(VGG16, self).__init__()
        self.c1 = Conv2D(filters=64, kernel_size=(3, 3), padding='same')  # 卷积层1
        self.b1 = BatchNormalization()  # BN层1
        self.a1 = Activation('relu')  # 激活层1
        self.c2 = Conv2D(filters=64, kernel_size=(3, 3), padding='same', )
        self.b2 = BatchNormalization()  # BN层1
        self.a2 = Activation('relu')  # 激活层1
        self.p1 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')
        self.d1 = Dropout(0.2)  # dropout层

        self.c3 = Conv2D(filters=128, kernel_size=(3, 3), padding='same')
        self.b3 = BatchNormalization()  # BN层1
        self.a3 = Activation('relu')  # 激活层1
        self.c4 = Conv2D(filters=128, kernel_size=(3, 3), padding='same')
        self.b4 = BatchNormalization()  # BN层1
        self.a4 = Activation('relu')  # 激活层1
        self.p2 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')
        self.d2 = Dropout(0.2)  # dropout层

        self.c5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same')
        self.b5 = BatchNormalization()  # BN层1
        self.a5 = Activation('relu')  # 激活层1
        self.c6 = Conv2D(filters=256, kernel_size=(3, 3), padding='same')
        self.b6 = BatchNormalization()  # BN层1
        self.a6 = Activation('relu')  # 激活层1
        self.c7 = Conv2D(filters=256, kernel_size=(3, 3), padding='same')
        self.b7 = BatchNormalization()
        self.a7 = Activation('relu')
        self.p3 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')
        self.d3 = Dropout(0.2)

        self.c8 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')
        self.b8 = BatchNormalization()  # BN层1
        self.a8 = Activation('relu')  # 激活层1
        self.c9 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')
        self.b9 = BatchNormalization()  # BN层1
        self.a9 = Activation('relu')  # 激活层1
        self.c10 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')
        self.b10 = BatchNormalization()
        self.a10 = Activation('relu')
        self.p4 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')
        self.d4 = Dropout(0.2)

        self.c11 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')
        self.b11 = BatchNormalization()  # BN层1
        self.a11 = Activation('relu')  # 激活层1
        self.c12 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')
        self.b12 = BatchNormalization()  # BN层1
        self.a12 = Activation('relu')  # 激活层1
        self.c13 = Conv2D(filters=512, kernel_size=(3, 3), padding='same')
        self.b13 = BatchNormalization()
        self.a13 = Activation('relu')
        self.p5 = MaxPool2D(pool_size=(2, 2), strides=2, padding='same')
        self.d5 = Dropout(0.2)

        self.flatten = Flatten()
        self.f1 = Dense(512, activation='relu')
        self.d6 = Dropout(0.2)
        self.f2 = Dense(512, activation='relu')
        self.d7 = Dropout(0.2)
        self.f3 = Dense(10, activation='softmax')

    def call(self, x):
        x = self.c1(x)
        x = self.b1(x)
        x = self.a1(x)
        x = self.c2(x)
        x = self.b2(x)
        x = self.a2(x)
        x = self.p1(x)
        x = self.d1(x)

        x = self.c3(x)
        x = self.b3(x)
        x = self.a3(x)
        x = self.c4(x)
        x = self.b4(x)
        x = self.a4(x)
        x = self.p2(x)
        x = self.d2(x)

        x = self.c5(x)
        x = self.b5(x)
        x = self.a5(x)
        x = self.c6(x)
        x = self.b6(x)
        x = self.a6(x)
        x = self.c7(x)
        x = self.b7(x)
        x = self.a7(x)
        x = self.p3(x)
        x = self.d3(x)

        x = self.c8(x)
        x = self.b8(x)
        x = self.a8(x)
        x = self.c9(x)
        x = self.b9(x)
        x = self.a9(x)
        x = self.c10(x)
        x = self.b10(x)
        x = self.a10(x)
        x = self.p4(x)
        x = self.d4(x)

        x = self.c11(x)
        x = self.b11(x)
        x = self.a11(x)
        x = self.c12(x)
        x = self.b12(x)
        x = self.a12(x)
        x = self.c13(x)
        x = self.b13(x)
        x = self.a13(x)
        x = self.p5(x)
        x = self.d5(x)

        x = self.flatten(x)
        x = self.f1(x)
        x = self.d6(x)
        x = self.f2(x)
        x = self.d7(x)
        y = self.f3(x)
        return y


model = VGG16()

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['sparse_categorical_accuracy'])

checkpoint_save_path = "./checkpoint/VGG16.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the model-----------------')
    model.load_weights(checkpoint_save_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True)

history = model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1,
                    callbacks=[cp_callback])
model.summary()

# print(model.trainable_variables)
file = open('./weights.txt', 'w')
for v in model.trainable_variables:
    file.write(str(v.name) + '\n')
    file.write(str(v.shape) + '\n')
    file.write(str(v.numpy()) + '\n')
file.close()

###############################################    show   ###############################################

# 显示训练集和验证集的acc和loss曲线
acc = history.history['sparse_categorical_accuracy']
val_acc = history.history['val_sparse_categorical_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()


确实有一些用户报告在使用Apple M1芯片的Mac上安装TensorFlow Metal后,模型的准确率下降的问题。这可能是由于TensorFlow Metal在当前版本下仍然处于早期阶段,并且可能存在一些尚未解决的问题。

有几个可能的解决方法可以尝试:

  1. 使用Rosetta 2模拟器:将TensorFlow回退到Intel架构版本,并通过Rosetta 2模拟器在M1芯片上运行。这可能可以避免性能和准确率下降的问题,但可能会牺牲一些性能。

  2. 等待更新版本:TensorFlow和TensorFlow Metal的开发人员正在积极工作,以改进和优化在M1芯片上的性能和兼容性。随着时间的推移,新的更新版本可能会提供更好的准确率和性能。

  3. 尝试其他框架:如果您是使用Mac上的深度学习框架,可以尝试使用其他支持M1芯片的框架,例如PyTorch或Apple自家的Core ML框架。这些框架可能在M1芯片上提供更好的性能和准确率。

请记住,M1芯片是相对较新的技术,尽管TensorFlow Metal已经发布,但在其上运行的框架和工具仍然在发展中。随着时间的推移,更多的优化和改进将使得在M1芯片上的机器学习任务更加稳定和可靠。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答由chatgpt基于相关博客总结生成:

    问题原因: 在安装了TensorFlow-Metal后,模型准确率下降到0.1左右的问题可能由两个主要原因引起。

    1. 兼容性问题:TensorFlow-Metal是专为苹果M1芯片优化的加速库,但它可能与原始的TensorFlow框架存在兼容性问题,导致性能下降或准确率降低。

    2. 加速方法问题:在使用TensorFlow-Metal加速时,可能需要进行一些特殊配置或调整参数,才能获得与原始TensorFlow相当的准确率和性能。

    解决方案: 要解决这个问题,可以尝试以下几个步骤:

    1. 更新TensorFlow版本: 确保您的TensorFlow版本是最新的。在终端中运行以下命令可以更新TensorFlow:
      pip install --upgrade tensorflow

    2. 检查TensorFlow-Metal的版本: 确保您安装的TensorFlow-Metal版本是最新的。在终端中运行以下命令可以安装或更新TensorFlow-Metal: pip install --upgrade tensorflow-metal

    3. 禁用TensorFlow-Metal并重新训练: 如果更新版本后问题仍然存在,您可以尝试禁用TensorFlow-Metal并重新训练模型。只需注释掉或删除代码中与TensorFlow-Metal有关的部分,然后再次运行代码:

    python # import tensorflow as tf # tf.config.experimental.set_virtual_device_configuration(tf.config.experimental.list_physical_devices('GPU')[0], # [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])

    1. 降低数据预处理: 缩放数据集时使用的/ 255.0操作可能会导致数值变化较大,从而影响模型的训练。可以尝试使用更小的缩放值,例如/ 127.5 - 1,然后重新训练模型。

    python # 数据预处理 x_train, x_test = x_train / 127.5 - 1, x_test / 127.5 - 1

    1. 降低学习率: 在使用硬件加速时,模型可能更快地收敛。这可能导致学习率过大,从而影响准确率。尝试减小学习率以更好地适应加速训练。

    python # 编译和训练模型 optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001) model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])

    如果上述步骤都不起作用,您可能需要等待TensorFlow-Metal社区或官方发布更新以解决兼容性问题。

    请注意,这些步骤仅为解决问题的一般指导,具体解决方案可能因环境和配置而异。如果问题仍然存在,建议查阅TensorFlow-Metal的官方文档、社区或在相关论坛寻求帮助。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

在M1 Mac上使用 TensorFlow 运行 VGG 网络时遇到的问题可能是由于使用了 TensorFlow Metal 导致的。尽管 TensorFlow Metal 可以提供硬件加速,但某些模型或操作可能不受支持或存在兼容性问题。

要解决这个问题,可以尝试以下几种方法:

  1. 确保安装的 TensorFlow 版本是与 TensorFlow Metal 兼容的最新版本,以获得最佳的硬件加速支持。

  2. 尝试运行更简单的模型或示例代码,以确定是特定于 VGG 网络的问题还是 TensorFlow Metal 的整体问题。

  3. 如果确认是 TensorFlow Metal 导致的问题,可以尝试使用 TensorFlow 的其他后端(如 TensorFlow CPU 或 TensorFlow GPU)来获得更好的准确率。

  4. 查看 TensorFlow Metal 的官方文档和社区支持,以了解是否有已知的问题或解决方案适用于你的情况。

另外,还可以尝试使用其他的深度学习框架来在 M1 Mac 上运行 VGG 网络,如 PyTorch、Apple's Core ML 或使用 Metal Performance Shaders 直接编写代码来实现相同的功能。这些框架可能提供更好的性能和兼容性。

希望以上信息对你有帮助!如有其他问题,请随时提问。