Does AWS Sagemaker supports gRPC prediction requests? - tensorflow

I deployed a Sagemaker's Tensorflow model from an estimator in local mode and when trying to call the Tensorflow Serving (TFS) predict endpoint using gRPC I get the error:
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
status = StatusCode.UNAVAILABLE
details = "failed to connect to all addresses"
Im doing the gRPC request exactly as in this blog post:
import grpc from tensorflow.compat.v1
import make_tensor_protofrom tensorflow_serving.apis
import predict_pb2from tensorflow_serving.apis
import prediction_service_pb2_grpc
grpc_port = 9000 # Tried also with other ports such as 8500
request = predict_pb2.PredictRequest()
request.model_spec.name = 'model'
request.model_spec.signature_name = 'serving_default'
request.inputs['input_tensor'].CopyFrom(make_tensor_proto(instance))
options = [
('grpc.enable_http_proxy', 0),
('grpc.max_send_message_length', MAX_GRPC_MESSAGE_LENGTH),
('grpc.max_receive_message_length', MAX_GRPC_MESSAGE_LENGTH)
]
channel = grpc.insecure_channel(f'0.0.0.0:{grpc_port}', options=options)
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
result_future = stub.Predict.future(request, 30)
output_tensor_proto = result_future.result().outputs['predictions']
output_shape = [dim.size for dim in output_tensor_proto.tensor_shape.dim]
output_np = np.array(output_tensor_proto.float_val).reshape(output_shape)
prediction_json = {'predictions': output_np.tolist()}
Looking at the Sagemaker's docker container where TFS is running, I see in the logs that the rest endpoint is exported/exposed, but not the gRPC one, although it seems to be running:
ensorflow_serving/model_servers/server.cc:417] Running gRPC ModelServer at 0.0.0.0:9000 ...
Unlike for gRPC, in the container logs I can see the rest endpoint is exported:
tensorflow_serving/model_servers/server.cc:438] Exporting HTTP/REST API at:localhost:8501 ...
Does Sagemaker TFS containers even support gRPC? How can one make a gRPC TFS prediction request using Sagemaker?

SageMaker endpoints are REST endpoints. You can however make gRPC connections within the container. You cannot make the InvokeEndpoint API call via gRPC.
If you are using the SageMaker TensorFlow container, you need to pass an inference.py script that contains the logic to make the gRPC request to TFS.
Kindly see this example inference.py script that makes a gRPC prediction against TensorFlow Serving.

Related

Failed in Tensorflow Serving gRPC reflection

I'm trying to add a gRPC health check endpoint in tensorflow serving. I added these code into tensorflow_serving/model_servers/server.cc and re-compiled it:
::grpc::EnableDefaultHealthCheckService(true);
::grpc::reflection::InitProtoReflectionServerBuilderPlugin();
After that I run it and test with grpcurl: grpcurl -plaintext localhost:8500 list
It shows:
grpc.health.v1.Health
grpc.reflection.v1alpha.ServerReflection
tensorflow.ProfilerService
tensorflow.serving.ModelService
tensorflow.serving.PredictionService
But when I try grpcurl -plaintext localhost:8500 grpc.health.v1.Health/Check
It says:
Error invoking method "grpc.health.v1.Health/Check": target server does not expose service "grpc.health.v1.Health"
It's quite a simple feature but have been stucking me for several days.
Could someone help? Thanks in advance!
Simply speaking, grpcurl relies on reflection service if you don't provide proto files and gRPC C++ doesn't expose reflection data for health service, which is why you got this head-scratching error in the first place.
$ grpcurl -plaintext 0.0.0.0:50051 grpc.health.v1.Health/Check
Error invoking method "grpc.health.v1.Health/Check": target server does not expose service "grpc.health.v1.Health"
grpcurl can do health-check call with health proto file present;
$ grpcurl -plaintext -proto=src/proto/grpc/health/v1/health.proto 0.0.0.0:50051 grpc.health.v1.Health/Check
{
"status": "SERVING"
}
Implementation-wise, gRPC C++ relies on protobuf description pool to implement its reflection service but health is based on upb which is not part of protobuf description pool. This is why gRPC C++ isn't able to expose the schema of health service.

How do you SSH into a Google Compute Engine VM instance with Python rather than the CLI?

I want to SSH into a GCE VM instance using the google-api-client. I am able to start an instance using google-api-client with the following code:
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
credentials = GoogleCredentials.get_application_default()
service = discovery.build('compute', 'v1', credentials=credentials)
project = 'my_project'
zone = 'us-west2-a'
instance = 'my_instance'
request = service.instances().start(project=project, zone=zone, instance=instance)
response = request.execute()
In the command line the above code is rendered as:
gcloud compute instances start my_instance
Similarly, to SSH into a GCE VM instance with the command line one writes:
gcloud init && gcloud compute ssh my_instance --project my_project --verbosity=debug --zone=us-west2-a
I've already got the SSH keys set up and all that.
I want to know how to write the above command line in Google Api Client or Python.
There is no official REST API method to connect to a Compute Engine instance with SSH. But assuming you have the SSH keys configured as per the documentation, in theory, you could use a third-party tool such as Paramiko. Take a look at this post for more details.

Fail to connect to VREP remote api in google colab

I want to connect to VREP using the python remote api in google colab. I tried to run the sample code below in jupyter notebook and it is working. However, when I change to google colab, the remote api fails to connect to VREP even though the code is the same.
import vrep
vrep.simxFinish(-1)
clientID = vrep.simxStart('127.0.0.1', 19997, True, True, 500, 5)
if clientID != -1: # if we connected successfully
print ('Connected to remote API server')
else:
print('Fail to connect')

S3 Python client with boto3 SDK

I'd like to make a python S3 client to store data in the S3 Dynamic Storage service provided by the appcloud. So I've discovered the boto3 SDK for python and was wondering how this thing works on the appcloud. Locally you install the aws cli to configure your credentials but how you do that on the cloud? Does someone have experience with creating a S3 python client for the internal appcloud and could provide me with a short example (boto3 or different approach)?
Greetings
Edit 1:
Tried this:
import boto3
s3 = boto3.client('s3', endpoint_url='https://ds31s3.swisscom.com/', aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET)
s3.create_bucket(Bucket="sc-testbucket1234")
But I got this exception:
botocore.exceptions.EndpointConnectionError: Could not connect to the endpoint URL: "https://ds31s3.swisscom.com"
import boto3
conn = boto3.resource('s3',
region_name='eu-west-1',
endpoint_url='https://x',
aws_access_key_id='xx',
aws_secret_access_key='xx',)
conn.create_bucket(Bucket="bucketname")
Works with this configuration (with python 3.5):
import boto3
conn = boto3.resource('s3', region_name='eu-west-1', endpoint_url=HOST, aws_access_key_id=KEY, aws_secret_access_key=SECRTE)
conn.create_bucket(Bucket="pqdjmalsdnf12098")
Thanks to #user3080315

Run Non-Twisted-based Python script daemonized with twistd

I'm writing a Python program consisting of a server (using Twisted) and a client (without Twisted)
The server part is implemented using Twisted and Twisted's application framework and launched with Twistd to be daemonized.
The client which runs on a different server is a simple Python script without any Twisted stuff (and no application framework specific stuff). It should also be run as a Daemon. FYI, this is the source:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import sys
import time
import syslog
SERVER_IP = '127.0.0.1'
SERVER_PORT = 43278
BEAT_PERIOD = 1
class HeartbeatClient:
'''
A Client sending heartbeats to a monitoring server.
'''
def __init__(self, server_ip, port, beat_period):
syslog.syslog( ('Sending heartbeat to IP %s , port %d' +
'\n press Ctrl-C to stop\n')
% (SERVER_IP, SERVER_PORT))
def run(self):
while True:
hbSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
hbSocket.sendto('PyHB', (SERVER_IP, SERVER_PORT))
if __debug__:
print 'Time: %s' % time.ctime()
time.sleep(BEAT_PERIOD)
if __name__ == '__main__':
hbc = HeartbeatClient()
hbc.run()
Now I wonder if I can daemonize the client also with Twistd? Therefore I would have create an Twisted-Application out of the client. But all examples I saw concerning Twisted applications where implementing some Twisted internet-server stuff (like in my case internet.UDPServer...), which my client does not use.
So is it possible to use Twistd to launch my client as a daemon, and what changes do I have to make? Should I rewrite the client to take full use of Twisted? If yes, are there any similar examples out there how to write a Twisted based network client?
Or do I have to use a different daemonize library for the client? There is a good library for that, but I'm trying to be consistent and use the same daemonizing mechanism for client and server.
With Twisted, as a tac file, your HeartbeatClient would look something like this:
from twisted.application.service import Application, Service
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
from twisted.internet.protocol import DatagramProtocol
class HeartbeatClient(Service):
def startService(self):
self._call = LoopingCall(self._heartbeat)
self._call.start(BEAT_PERIOD)
def stopService(self):
self._call.stop()
def _heartbeat(self):
port = reactor.listenUDP(0, DatagramProtocol())
port.write('PyHB', (SERVER_IP, SERVER_PORT))
port.stopListening()
application = Application("PyHB")
HeartbeatClient().setServiceParent(application)
Note the use of reactor.listenUDP, even though you're only sending UDP datagrams, not receiving any. UDP doesn't really have the concept of clients and servers, it only has open ports. All UDP ports can send and receive datagrams. That's why there's only reactor.listenUDP, not reactor.connectUDP.
Aside from that, LoopingCall gives you the loop you want, and putting the code into a custom Service subclass lets you start and stop the loop at the appropriate times.