Skip to content
8 changes: 7 additions & 1 deletion pkg/cli/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var buildSeparateWeights bool
var buildSecrets []string
var buildNoCache bool
var buildProgressOutput string
var buildUseCudaBaseImage string

func newBuildCommand() *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -27,6 +28,7 @@ func newBuildCommand() *cobra.Command {
addSecretsFlag(cmd)
addNoCacheFlag(cmd)
addSeparateWeightsFlag(cmd)
addUseCudaBaseImageFlag(cmd)
cmd.Flags().StringVarP(&buildTag, "tag", "t", "", "A name for the built image in the form 'repository:tag'")
return cmd
}
Expand All @@ -45,7 +47,7 @@ func buildCommand(cmd *cobra.Command, args []string) error {
imageName = config.DockerImageName(projectDir)
}

if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildProgressOutput); err != nil {
if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildUseCudaBaseImage, buildProgressOutput); err != nil {
return err
}

Expand Down Expand Up @@ -73,3 +75,7 @@ func addNoCacheFlag(cmd *cobra.Command) {
func addSeparateWeightsFlag(cmd *cobra.Command) {
cmd.Flags().BoolVar(&buildSeparateWeights, "separate-weights", false, "Separate model weights from code in image layers")
}

func addUseCudaBaseImageFlag(cmd *cobra.Command) {
cmd.Flags().StringVar(&buildUseCudaBaseImage, "use-cuda-base-image", "auto", "Use Nvidia CUDA base image, 'true' (default) or 'false' (use python base image). False results in a smaller image but may cause problems for non-torch projects")
}
3 changes: 3 additions & 0 deletions pkg/cli/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func newDebugCommand() *cobra.Command {
}

addSeparateWeightsFlag(cmd)
addUseCudaBaseImageFlag(cmd)
cmd.Flags().StringVarP(&imageName, "image-name", "", "", "The image name to use for the generated Dockerfile")

return cmd
Expand All @@ -43,6 +44,8 @@ func cmdDockerfile(cmd *cobra.Command, args []string) error {
}
}()

generator.SetUseCudaBaseImage(buildUseCudaBaseImage)

if buildSeparateWeights {
if imageName == "" {
imageName = config.DockerImageName(projectDir)
Expand Down
5 changes: 4 additions & 1 deletion pkg/cli/predict.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ the prediction on that.`,
Args: cobra.MaximumNArgs(1),
SuggestFor: []string{"infer"},
}

addUseCudaBaseImageFlag(cmd)
addBuildProgressOutputFlag(cmd)

cmd.Flags().StringArrayVarP(&inputFlags, "input", "i", []string{}, "Inputs, in the form name=value. if value is prefixed with @, then it is read from a file on disk. E.g. -i path=@image.jpg")
cmd.Flags().StringVarP(&outPath, "output", "o", "", "Output path")

Expand All @@ -63,7 +66,7 @@ func cmdPredict(cmd *cobra.Command, args []string) error {
return err
}

if imageName, err = image.BuildBase(cfg, projectDir, buildProgressOutput); err != nil {
if imageName, err = image.BuildBase(cfg, projectDir, buildUseCudaBaseImage, buildProgressOutput); err != nil {
return err
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/cli/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ func newPushCommand() *cobra.Command {
RunE: push,
Args: cobra.MaximumNArgs(1),
}
addBuildProgressOutputFlag(cmd)
addSecretsFlag(cmd)
addNoCacheFlag(cmd)
addSeparateWeightsFlag(cmd)
addUseCudaBaseImageFlag(cmd)
addBuildProgressOutputFlag(cmd)

return cmd
}
Expand All @@ -45,7 +46,7 @@ func push(cmd *cobra.Command, args []string) error {
return fmt.Errorf("To push images, you must either set the 'image' option in cog.yaml or pass an image name as an argument. For example, 'cog push registry.hooli.corp/hotdog-detector'")
}

if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildProgressOutput); err != nil {
if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildUseCudaBaseImage, buildProgressOutput); err != nil {
return err
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func newRunCommand() *cobra.Command {
Args: cobra.MinimumNArgs(1),
}
addBuildProgressOutputFlag(cmd)
addUseCudaBaseImageFlag(cmd)

flags := cmd.Flags()
// Flags after first argment are considered args and passed to command
Expand All @@ -42,7 +43,7 @@ func run(cmd *cobra.Command, args []string) error {
return err
}

imageName, err := image.BuildBase(cfg, projectDir, buildProgressOutput)
imageName, err := image.BuildBase(cfg, projectDir, buildUseCudaBaseImage, buildProgressOutput)
if err != nil {
return err
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/cli/train.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ It will build the model in the current directory and train it.`,
Args: cobra.MaximumNArgs(1),
Hidden: true,
}

addBuildProgressOutputFlag(cmd)
addUseCudaBaseImageFlag(cmd)

cmd.Flags().StringArrayVarP(&trainInputFlags, "input", "i", []string{}, "Inputs, in the form name=value. if value is prefixed with @, then it is read from a file on disk. E.g. -i path=@image.jpg")

return cmd
Expand All @@ -48,7 +51,7 @@ func cmdTrain(cmd *cobra.Command, args []string) error {
return err
}

if imageName, err = image.BuildBase(cfg, projectDir, buildProgressOutput); err != nil {
if imageName, err = image.BuildBase(cfg, projectDir, buildUseCudaBaseImage, buildProgressOutput); err != nil {
return err
}

Expand Down
28 changes: 18 additions & 10 deletions pkg/dockerfile/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type Generator struct {
GOOS string
GOARCH string

useCudaBaseImage bool

// absolute path to tmpDir, a directory that will be cleaned up
tmpDir string
// tmpDir relative to Dir
Expand All @@ -73,16 +75,22 @@ func NewGenerator(config *config.Config, dir string) (*Generator, error) {
}

return &Generator{
Config: config,
Dir: dir,
GOOS: runtime.GOOS,
GOARCH: runtime.GOOS,
tmpDir: tmpDir,
relativeTmpDir: relativeTmpDir,
fileWalker: filepath.Walk,
Config: config,
Dir: dir,
GOOS: runtime.GOOS,
GOARCH: runtime.GOOS,
tmpDir: tmpDir,
relativeTmpDir: relativeTmpDir,
fileWalker: filepath.Walk,
useCudaBaseImage: true,
}, nil
}

func (g *Generator) SetUseCudaBaseImage(argumentValue string) {
// "false" -> false, "true" -> true, "auto" -> true, "asdf" -> true
g.useCudaBaseImage = argumentValue != "false"
}

func (g *Generator) GenerateBase() (string, error) {
baseImage, err := g.baseImage()
if err != nil {
Expand Down Expand Up @@ -158,7 +166,7 @@ func (g *Generator) Generate(imageName string) (weightsBase string, dockerfile s
return "", "", "", err
}
installPython := ""
if g.Config.Build.GPU {
if g.Config.Build.GPU && g.useCudaBaseImage {
installPython, err = g.installPythonCUDA()
if err != nil {
return "", "", "", err
Expand Down Expand Up @@ -245,10 +253,10 @@ func (g *Generator) Cleanup() error {
}

func (g *Generator) baseImage() (string, error) {
if g.Config.Build.GPU {
if g.Config.Build.GPU && g.useCudaBaseImage {
return g.Config.CUDABaseImageTag()
}
return "python:" + g.Config.Build.PythonVersion, nil
return "python:" + g.Config.Build.PythonVersion + "-slim", nil
}

func (g *Generator) preamble() string {
Expand Down
8 changes: 4 additions & 4 deletions pkg/dockerfile/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ predict: predict.py:Predictor
expected := `#syntax=docker/dockerfile:1.4
FROM r8.im/replicate/cog-test-weights AS weights
` + testTiniStage() +
`FROM python:3.8
`FROM python:3.8-slim
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/usr/local/nvidia/lib64:/usr/local/nvidia/bin
Expand Down Expand Up @@ -152,7 +152,7 @@ predict: predict.py:Predictor
expected := `#syntax=docker/dockerfile:1.4
FROM r8.im/replicate/cog-test-weights AS weights
` + testTiniStage() +
`FROM python:3.8
`FROM python:3.8-slim
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/usr/local/nvidia/lib64:/usr/local/nvidia/bin
Expand Down Expand Up @@ -248,7 +248,7 @@ build:
expected := `#syntax=docker/dockerfile:1.4
FROM r8.im/replicate/cog-test-weights AS weights
` + testTiniStage() +
`FROM python:3.8
`FROM python:3.8-slim
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/usr/local/nvidia/lib64:/usr/local/nvidia/bin
Expand Down Expand Up @@ -428,7 +428,7 @@ predict: predict.py:Predictor

expected := `#syntax=docker/dockerfile:1.4
` + testTiniStage() +
`FROM python:3.8
`FROM python:3.8-slim
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/usr/local/nvidia/lib64:/usr/local/nvidia/bin
Expand Down
8 changes: 6 additions & 2 deletions pkg/image/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const dockerignoreBackupPath = ".dockerignore.cog.bak"
// Build a Cog model from a config
//
// This is separated out from docker.Build(), so that can be as close as possible to the behavior of 'docker build'.
func Build(cfg *config.Config, dir, imageName string, secrets []string, noCache, separateWeights bool, progressOutput string) error {
func Build(cfg *config.Config, dir, imageName string, secrets []string, noCache, separateWeights bool, useCudaBaseImage string, progressOutput string) error {
console.Infof("Building Docker image from environment in cog.yaml as %s...", imageName)

generator, err := dockerfile.NewGenerator(cfg, dir)
Expand All @@ -32,6 +32,7 @@ func Build(cfg *config.Config, dir, imageName string, secrets []string, noCache,
console.Warnf("Error cleaning up Dockerfile generator: %s", err)
}
}()
generator.SetUseCudaBaseImage(useCudaBaseImage)

if separateWeights {
weightsDockerfile, runnerDockerfile, dockerignore, err := generator.Generate(imageName)
Expand Down Expand Up @@ -110,7 +111,7 @@ func Build(cfg *config.Config, dir, imageName string, secrets []string, noCache,
return nil
}

func BuildBase(cfg *config.Config, dir string, progressOutput string) (string, error) {
func BuildBase(cfg *config.Config, dir string, useCudaBaseImage string, progressOutput string) (string, error) {
// TODO: better image management so we don't eat up disk space
// https://github.com/replicate/cog/issues/80
imageName := config.BaseDockerImageName(dir)
Expand All @@ -125,6 +126,9 @@ func BuildBase(cfg *config.Config, dir string, progressOutput string) (string, e
console.Warnf("Error cleaning up Dockerfile generator: %s", err)
}
}()

generator.SetUseCudaBaseImage(useCudaBaseImage)

dockerfileContents, err := generator.GenerateBase()
if err != nil {
return "", fmt.Errorf("Failed to generate Dockerfile: %w", err)
Expand Down
1 change: 1 addition & 0 deletions pkg/util/mime/mime.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ var typeToExtension = map[string]string{
"font/woff2": ".woff2",

"image/bmp": ".bmp",
"image/x-ms-bmp": ".bmp",
"image/gif": ".gif",
"image/jpeg": ".jpg",
"image/png": ".png",
Expand Down