I’m working on the Digit problem. Since the data is given in csv format, to convert it to an image, I wrote a custom class :
class CustomImageList(ImageList):
def open(self, fn):
img = fn.reshape(28,28)
img = np.stack((img,)*3, axis=-1)
return Image(pil2tensor(img, dtype=np.float32))
@classmethod
def from_csv_custom(cls, path:PathOrStr, csv_name:str, imgIdx:int=1, header:str='infer', **kwargs)->'ItemList':
df = pd.read_csv(Path(path)/csv_name, header=header)
res = super().from_df(df, path=path, cols=0, **kwargs)
res.items = df.iloc[:,imgIdx:].apply(lambda x: x.values / 255.0, axis=1).values
return res
@classmethod
def from_df_custom(cls, path:PathOrStr, df:DataFrame, imgIdx:int=1, header:str='infer', **kwargs)->'ItemList':
res = super().from_df(df, path=path, cols=0, **kwargs)
res.items = df.iloc[:,imgIdx:].apply(lambda x: x.values / 255.0, axis=1).values
return res
I call it simply how we would call our Data Block API. Everything seems to run fine. I exported my pkl file too. Now when I am trying to run this on Heroku, I get the following error in my logs :
AttributeError: Can't get attribute 'CustomImageList' on <module '__main__' from 'app/server.py'>
Can any one help here?
Edit : Adding my serve.py code too :
import aiohttp
import asyncio
import uvicorn
from fastai import *
from fastai.vision import *
from io import BytesIO
from starlette.applications import Starlette
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import HTMLResponse, JSONResponse
from starlette.staticfiles import StaticFiles
export_file_url = 'https://www.googleapis.com/drive/v3/files/1iRYfxkbrmHoAiV6aJbiLoaEOyXdERBe1?alt=media&key=AIzaSyA1CbVi3ynikmMs4KXq1xXnHSol27UaQ2U'
export_file_name = 'export.pkl'
Port = int(os.environ.get('PORT', 50000))
classes = ['0','1','2','3','4','5','6','7','8','9']
path = Path(__file__).parent
app = Starlette()
app.add_middleware(CORSMiddleware, allow_origins=['*'], allow_headers=['X-Requested-With', 'Content-Type'])
app.mount('/static', StaticFiles(directory='app/static'))
async def download_file(url, dest):
if dest.exists(): return
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
data = await response.read()
with open(dest, 'wb') as f:
f.write(data)
async def setup_learner():
await download_file(export_file_url, path / export_file_name)
try:
learn = load_learner(path, export_file_name)
return learn
except RuntimeError as e:
if len(e.args) > 0 and 'CPU-only machine' in e.args[0]:
print(e)
message = "\n\nThis model was trained with an old version of fastai and will not work in a CPU environment.\n\nPlease update the fastai library in your training environment and export your model again.\n\nSee instructions for 'Returning to work' at https://course.fast.ai."
raise RuntimeError(message)
else:
raise
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(setup_learner())]
learn = loop.run_until_complete(asyncio.gather(*tasks))[0]
loop.close()
@app.route('/')
async def homepage(request):
html_file = path / 'view' / 'index.html'
return HTMLResponse(html_file.open().read())
@app.route('/analyze', methods=['POST'])
async def analyze(request):
img_data = await request.form()
img_bytes = await (img_data['file'].read())
img = open_image(BytesIO(img_bytes))
prediction = learn.predict(img)[0]
return JSONResponse({'result': str(prediction)})
if __name__ == '__main__':
if 'serve' in sys.argv:
uvicorn.run(app=app, host='0.0.0.0', port=Port, log_level="info")
Sorry for the long post !