前言
打算把clip模型转成tensorflow,并且将输入修改成web友好地的base64(模型内置预处理层)以便tf-serving上部署供外部api调用。
问题描述
clip代码库中图片预处理是使用pytorch的transforms库完成的,实际上这个库属于pillow的包装库,最后仍然是使用pillow完成的图像处理。
from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
def _transform(n_px):
return Compose([
Resize(n_px, interpolation=BICUBIC),
CenterCrop(n_px),
_convert_image_to_rgb,
ToTensor(),
Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)),
])
整个处理流程是以较小边为基准,将较小边缩放到npx,且保持整体比例不变,缩放的插值算法为bicubic,再进行居中裁剪,再将图片转为rgb模型,最后除255转为tensor后再使用指定均值和方差进行了标准化。
对应的缩放代码,将其改为tensorflow代码,直觉上应该是使用
tf.image.resize()
但是这个resize方法默认会进行压缩,如果选择保持比例,则会将更大的边和你预定值对齐。
tf.image.resize(imgs_map, [224, 224],method='bicubic',antialias=True,preserve_aspect_ratio=False) | |
tf.image.resize(imgs_map, [224, 224],method='bicubic',antialias=True,preserve_aspect_ratio=True) |
注意到tf的图像预处理层中有
tf.keras.layers.Resizing
当其crop_to_aspect_ratio=True时,可以做到一样的缩放行为,但是这个layer的初始化参数并没有抗锯齿的选项,pillow缩放图片时默认应用了抗锯齿。
transforms | |
tf.keras.layers.Resizing( 224, 224,interpolation='bicubic',crop_to_aspect_ratio=True) |
之后观察tf.keras.layers.Resizing的源码,得知实际上这个智能缩放行为是通过先裁剪后缩放(调用tf.image.resize)实现的,因为拷贝了下源码,修改了调用tf.image.resize时的参数,最后效果
transforms | |
tensorflow |
肉眼观察实际上已经非常接近,但是通过图像矩阵相减发现实际上差别还是很大,可以看到边缘明显有白色线条。
TensorFlow - pytorch transforms | |
Pillow - pytorch transforms |
讨论
https://zuru.tech/blog/the-dangers-behind-image-resizing
大概的原因就是下采样行为的不一致
Comments | NOTHING