Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to Force-load TensorFlowLiteSelectTfOps.framework, created with Selective Build, in iOS #67790

Open
tanpengshi opened this issue May 17, 2024 · 5 comments
Assignees
Labels
comp:lite TF Lite related issues TF2.14 For issues related to Tensorflow 2.14.x type:build/install Build and install issues type:support Support issues

Comments

@tanpengshi
Copy link

tanpengshi commented May 17, 2024

IDE: Xcode 15
Platform: iOS17
TensorFlow version: r2.14

I am developing both iOS and Android apps that are running with TensorFlow Lite model. Because my model uses LSTM, I have to make use of TFSelectOps.

In addition, because the TensorFlowLiteSelectTFOps library is large in memory size, I have to do a selective build. After much effort, I have succeeded in making my TensorFlowLite model running smoothly on the Android app based on the selectively built libraries.

On the iOS however, I used a bazel build:

bash tensorflow/lite/ios/build_frameworks.sh
--input_models=model1.tflite,model2.tflite
--target_archs=x86_64,armv7,arm64

to generate the:

  1. TensorFlowLiteSelectTfOps.framework
  2. TensorFlowLiteC.framework

After that I edited the TensorFlowLiteSwift.podspec to include the framework:

Pod::Spec.new do |s|
  s.name             = 'TensorFlowLiteSwift'
  s.version          = '2.14.0'
  s.authors          = 'Google Inc.'
  s.license          = { :type => 'Apache' }
  s.homepage         = 'https://github.com/tensorflow/tensorflow'
  s.source           = { :git => 'https://github.com/tensorflow/tensorflow.git', :tag => "v#{s.version}" }
  s.summary          = 'TensorFlow Lite for Swift'
  s.description      = <<-DESC

  TensorFlow Lite is TensorFlow's lightweight solution for Swift developers. It
  enables low-latency inference of on-device machine learning models with a
  small binary size and fast performance supporting hardware acceleration.
                       DESC

  s.ios.deployment_target = '17.0'

  s.module_name = 'TensorFlowLite'
  s.static_framework = true

  tfl_dir = 'tensorflow/lite/'
  swift_dir = tfl_dir + 'swift/'

  s.default_subspec = 'Core'

  s.subspec 'Core' do |core|
    # Adjust the path to point to your custom frameworks
    core.vendored_frameworks = [
      'frameworks/TensorFlowLiteC.framework',
      'frameworks/TensorFlowLiteSelectTfOps.framework'
    ]
    
    core.source_files = swift_dir + 'Sources/*.swift'
    core.exclude_files = swift_dir + 'Sources/{CoreML,Metal}Delegate.swift'

    core.test_spec 'Tests' do |ts|
      ts.source_files = swift_dir + 'Tests/*.swift'
      ts.exclude_files = swift_dir + 'Tests/MetalDelegateTests.swift'
      ts.resources = [
        tfl_dir + 'testdata/add.bin',
        tfl_dir + 'testdata/add_quantized.bin',
      ]
    end
  end

  s.subspec 'CoreML' do |coreml|
    coreml.source_files = swift_dir + 'Sources/CoreMLDelegate.swift'
    coreml.dependency 'TensorFlowLiteSwift/Core', "#{s.version}"
  end

  s.subspec 'Metal' do |metal|
    metal.source_files = swift_dir + 'Sources/MetalDelegate.swift'
    metal.dependency 'TensorFlowLiteSwift/Core', "#{s.version}"

    metal.test_spec 'Tests' do |ts|
      ts.source_files = swift_dir + 'Tests/{Interpreter,MetalDelegate}Tests.swift'
      ts.resources = [
        tfl_dir + 'testdata/add.bin',
        tfl_dir + 'testdata/add_quantized.bin',
        tfl_dir + 'testdata/multi_add.bin',
      ]
    end
  end
end

I then do in the Podfile:

pod 'TensorFlowLiteSwift', :path => '../../local-podspecs/TensorFlowLiteSwift.podspec'

Then in terminal:

pod install

In my Other Linker Flags, i put:
-force_load $(SRCROOT)/local-podspecs/frameworks/TensorFlowLiteSelectTfOps.framework/TensorFlowLiteSelectTfOps

But when I do build, i get lots of errors below:

FacialRecognition
Undefined symbol: google::protobuf::TextFormat::PrintToString(google::protobuf::Message const&, std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>*)

Undefined symbol: google::protobuf::TextFormat::Parse(google::protobuf::io::ZeroCopyInputStream*, google::protobuf::Message*)

Undefined symbol: google::protobuf::DoubleValue::MergePartialFromCodedStream(google::protobuf::io::CodedInputStream*)

Undefined symbol: google::protobuf::DoubleValue::MergeFrom(google::protobuf::DoubleValue const&)

Undefined symbol: google::protobuf::DoubleValue::DoubleValue(google::protobuf::DoubleValue const&)

Undefined symbol: google::protobuf::MessageLite::ParseFromArray(void const*, int)

Undefined symbol: google::protobuf::MessageLite::ParseFromString(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&)

Undefined symbol: google::protobuf::MessageLite::ParseFromCodedStream(google::protobuf::io::CodedInputStream*)

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::RepeatedField::Swap(google::protobuf::RepeatedField*)

Undefined symbol: google::protobuf::RepeatedField::Reserve(int)

Undefined symbol: google::protobuf::RepeatedField::~RepeatedField()

Undefined symbol: google::protobuf::FieldDescriptor::TypeOnceInit(google::protobuf::FieldDescriptor const*)

Undefined symbol: google::protobuf::FieldDescriptor::kCppTypeToName

Undefined symbol: google::protobuf::FieldDescriptor::kTypeToCppTypeMap

Undefined symbol: google::protobuf::UnknownFieldSet::ClearFallback()

Undefined symbol: google::protobuf::UnknownFieldSet::MergeFrom(google::protobuf::UnknownFieldSet const&)

Undefined symbol: google::protobuf::RepeatedPtrField<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>>::~RepeatedPtrField()

Undefined symbol: google::protobuf::Any_default_instance

Undefined symbol: google::protobuf::BoolValue_default_instance

Undefined symbol: google::protobuf::io::CodedInputStream::SkipFallback(int, int)

Undefined symbol: google::protobuf::io::CodedInputStream::ReadTagFallback(unsigned int)

Undefined symbol: google::protobuf::io::CodedInputStream::ReadVarint32Fallback(unsigned int)

Undefined symbol: google::protobuf::io::CodedInputStream::ReadVarint64Fallback()

Undefined symbol: google::protobuf::io::CodedInputStream::GetDirectBufferPointer(void const**, int*)

Undefined symbol: google::protobuf::io::CodedInputStream::default_recursion_limit_

Undefined symbol: google::protobuf::io::CodedInputStream::ReadLittleEndian32Fallback(unsigned int*)

Undefined symbol: google::protobuf::io::CodedInputStream::ReadLittleEndian64Fallback(unsigned long long*)

Undefined symbol: google::protobuf::io::CodedInputStream::ReadVarintSizeAsIntFallback()

Undefined symbol: google::protobuf::io::CodedInputStream::DecrementRecursionDepthAndPopLimit(int)

Undefined symbol: google::protobuf::io::CodedInputStream::IncrementRecursionDepthAndPushLimit(int)

Undefined symbol: google::protobuf::io::CodedInputStream::ReadRaw(void*, int)

Undefined symbol: google::protobuf::io::CodedInputStream::Refresh()

Undefined symbol: google::protobuf::io::CodedInputStream::PopLimit(int)

Undefined symbol: google::protobuf::io::CodedInputStream::PushLimit(int)

Undefined symbol: google::protobuf::io::CodedInputStream::~CodedInputStream()

Undefined symbol: google::protobuf::io::ArrayOutputStream::ArrayOutputStream(void*, int, int)

Undefined symbol: google::protobuf::io::CodedOutputStream::EnableAliasing(bool)

Undefined symbol: google::protobuf::io::CodedOutputStream::WriteVarint32SlowPath(unsigned int)

Undefined symbol: google::protobuf::io::CodedOutputStream::WriteVarint64SlowPath(unsigned long long)

Undefined symbol: google::protobuf::io::CodedOutputStream::WriteStringWithSizeToArray(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, unsigned char*)

Undefined symbol: google::protobuf::io::CodedOutputStream::CodedOutputStream(google::protobuf::io::ZeroCopyOutputStream*)

Undefined symbol: google::protobuf::io::CodedOutputStream::~CodedOutputStream()

Undefined symbol: google::protobuf::io::ZeroCopyOutputStream::WriteAliasedRaw(void const*, int)

Undefined symbol: google::protobuf::DoubleValue_default_instance

Undefined symbol: google::protobuf::Any::MergePartialFromCodedStream(google::protobuf::io::CodedInputStream*)

Undefined symbol: google::protobuf::Any::Clear()

Undefined symbol: google::protobuf::Any::MergeFrom(google::protobuf::Any const&)

Undefined symbol: google::protobuf::Any::Any(google::protobuf::Any const&)

Undefined symbol: google::protobuf::DoubleValue* google::protobuf::Arena::CreateMaybeMessagegoogle::protobuf::DoubleValue(google::protobuf::Arena*)

Undefined symbol: google::protobuf::Any* google::protobuf::Arena::CreateMaybeMessagegoogle::protobuf::Any(google::protobuf::Arena*)

Undefined symbol: google::protobuf::BoolValue* google::protobuf::Arena::CreateMaybeMessagegoogle::protobuf::BoolValue(google::protobuf::Arena*)

Undefined symbol: google::protobuf::Message::DiscardUnknownFields()

Undefined symbol: google::protobuf::Message::CheckTypeAndMergeFrom(google::protobuf::MessageLite const&)

Undefined symbol: google::protobuf::Message::CopyFrom(google::protobuf::Message const&)

Undefined symbol: google::protobuf::Message::MergeFrom(google::protobuf::Message const&)

Undefined symbol: google::protobuf::internal::LogMessage::LogMessage(google::protobuf::LogLevel, char const*, int)

Undefined symbol: google::protobuf::internal::LogMessage::~LogMessage()

Undefined symbol: google::protobuf::internal::LogMessage::operator<<(char const*)

Undefined symbol: google::protobuf::internal::LogMessage::operator<<(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&)

Undefined symbol: google::protobuf::internal::LogMessage::operator<<(long long)

Undefined symbol: google::protobuf::internal::NameOfEnum(google::protobuf::EnumDescriptor const*, int)

Undefined symbol: google::protobuf::internal::WireFormat::SerializeUnknownFields(google::protobuf::UnknownFieldSet const&, google::protobuf::io::CodedOutputStream*)

Undefined symbol: google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(google::protobuf::UnknownFieldSet const&)

Undefined symbol: google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(google::protobuf::UnknownFieldSet const&, unsigned char*)

Undefined symbol: google::protobuf::internal::WireFormat::SkipField(google::protobuf::io::CodedInputStream*, unsigned int, google::protobuf::UnknownFieldSet*)

Undefined symbol: google::protobuf::internal::GenericSwap(google::protobuf::MessageLite*, google::protobuf::MessageLite*)

Undefined symbol: google::protobuf::internal::InitSCCImpl(google::protobuf::internal::SCCInfoBase*)

Undefined symbol: google::protobuf::internal::LogFinisher::operator=(google::protobuf::internal::LogMessage&)

Undefined symbol: google::protobuf::internal::MapFieldBase::SetMapDirty()

Undefined symbol: google::protobuf::internal::MapFieldBase::~MapFieldBase()

Undefined symbol: google::protobuf::internal::OnShutdownRun(void ()(void const), void const*)

Undefined symbol: google::protobuf::internal::ReflectionOps::Merge(google::protobuf::Message const&, google::protobuf::Message*)

Undefined symbol: google::protobuf::internal::VerifyVersion(int, int, char const*)

Undefined symbol: google::protobuf::internal::AddDescriptors(google::protobuf::internal::DescriptorTable const*)

Undefined symbol: google::protobuf::internal::DestroyMessage(void const*)

Undefined symbol: google::protobuf::internal::WireFormatLite::UInt32Size(google::protobuf::RepeatedField const&)

Undefined symbol: google::protobuf::internal::WireFormatLite::UInt64Size(google::protobuf::RepeatedField const&)

Undefined symbol: google::protobuf::internal::WireFormatLite::WriteBytes(int, std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, google::protobuf::io::CodedOutputStream*)

Undefined symbol: google::protobuf::internal::WireFormatLite::WriteFloat(int, float, google::protobuf::io::CodedOutputStream*)

Undefined symbol: google::protobuf::internal::WireFormatLite::WriteInt32(int, int, google::protobuf::io::CodedOutputStream*)

Undefined symbol: google::protobuf::internal::WireFormatLite::WriteInt64(int, long long, google::protobuf::io::CodedOutputStream*)

Undefined symbol: google::protobuf::internal::WireFormatLite::WriteDouble(int, double, google::protobuf::io::CodedOutputStream*)

Linker command failed with exit code 1 (use -v to see invocation)

@tilakrayal tilakrayal added TF2.14 For issues related to Tensorflow 2.14.x type:bug Bug comp:lite TF Lite related issues labels May 17, 2024
@tilakrayal tilakrayal assigned sawantkumar and unassigned tilakrayal May 20, 2024
@tanpengshi
Copy link
Author

I would appreciate any working solution to this, as long i can run my model on Select Ops based on a TensorFlowLiteSelectTFOps library selectively built based on the tflite model itself. Thanks a lot in advance! :)

@sawantkumar sawantkumar assigned pkgoogle and unassigned sawantkumar May 22, 2024
@pkgoogle
Copy link

pkgoogle commented May 28, 2024

Hi @tanpengshi, it looks like the system is unable to properly link the google protobuf library ... can you ensure you are following all the directions here correctly: https://www.tensorflow.org/lite/guide/build_ios#using_local_swift_or_objective-c_apis

particularly I see that your path does not point to the TF root directory

pod 'TensorFlowLiteSwift', :path => '../../local-podspecs/TensorFlowLiteSwift.podspec'

Where as the source says:

pod 'TensorFlowLiteSwift', :path => '<your_tensorflow_root_dir>'

Let me know if that works. Thanks.

@pkgoogle pkgoogle added stat:awaiting response Status - Awaiting response from author type:build/install Build and install issues type:support Support issues and removed type:bug Bug labels May 28, 2024
@tanpengshi
Copy link
Author

tanpengshi commented May 29, 2024

I have tried the above and I am still getting the same error. In addition I did :

  pod 'TensorFlowLiteSwift'
  pod 'TensorFlowLiteSelectTfOps', '~> 0.0.1-nightly'

Then replace i replaced the TensorFlowLiteSelectTfOps.framework with my selectively build TensorFlowLiteSelectTfOps.framework, and I still get the same error when building! I suspect the error comes inherently from the selectively built framework. Are you able to replicate the error I get?

Thank you!

@google-ml-butler google-ml-butler bot removed the stat:awaiting response Status - Awaiting response from author label May 29, 2024
@pkgoogle
Copy link

Hi @tanpengshi, are you willing to share your model(s) that are used to make your selective build? I'm wondering if any particular ops are causing the issue. Perhaps you can just make a dummy model which includes at least one of all the ops you are using and share that.

@pkgoogle pkgoogle added the stat:awaiting response Status - Awaiting response from author label May 30, 2024
@tanpengshi
Copy link
Author

tflite_CNN_LSTM_dummy.zip

Hi @pkgoogle, here is the dummy model that contains all the ops!

@google-ml-butler google-ml-butler bot removed the stat:awaiting response Status - Awaiting response from author label May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:lite TF Lite related issues TF2.14 For issues related to Tensorflow 2.14.x type:build/install Build and install issues type:support Support issues
Projects
None yet
Development

No branches or pull requests

4 participants