You cannot. From `:h 'number'` (emphasis mine):

> Print the line number in front of ***each line***

You can only enable `number` or `relativenumber` for the whole window.

See:

    :help 'number'
    :help 'relativenumber'


**Edit:**

In Vim, this isn't feasible because `'signcolumn'` has a max width of 2 characters. However, if you're using NeoVim, it can be feasibly done because the `'signcolumn'` options supports a width of up to 9, so unless you're editing files with > 1 billion lines, there is enough space for line numbers.

This might be easier done in Lua (I don't know, I've never written a Lua plugin for Nvim), but here is a solution in Vimscript. No guarantees about performance or "correctness" (it's kind of just thrown together), but it appears to work, let me know if I've missed some bug (spoiler for brevity):

    let g:custom_number_delimiter='##'
    let s:sign_id=500 " script level variable of current sign ID
    
    function! number#get_section_lines() abort
        " save cursor pos to restore
        let l:cursor_pos=[line('.'), col('.')]
    
        " Get line number by:
        " 1. :g/re/p for start of sections
        " 2. split output of :g/re/p into List
        " 3. isolate line numbers from output
        let l:section_start_lnums=number#isolate_lnums(split(execute('g/' . g:custom_number_delimiter . '.\+' . g:custom_number_delimiter . '/p#'), "\n"))
    
        " no matches
        if len(l:section_start_lnums) == 0
            return []
        endif
    
        " restore cursor pos (:g/re/p moves to last match, be nice and put it back)
        call cursor(cursor_pos)
    
        " build list of ranges in the format [[range_start_line, range_end_line], ...]
        let l:prev_lnum=-1
        let l:curr_lnum=-1
        let l:sections=[]
        for lnum in l:section_start_lnums
            let l:prev_lnum=l:curr_lnum
            let l:curr_lnum=lnum
    
            if l:prev_lnum != -1
                call add(l:sections, [l:prev_lnum, l:curr_lnum-1])
            endif
        endfor
    
        " logically, final section extends to end of file
        call add(l:sections, [l:curr_lnum, line('$')])
    
        return l:sections
    endfunction
    
    " gradually trim line until only the line number remains
    function! number#isolate_lnums(section_lines) abort
        if a:section_lines[0] =~ "Pattern not found"
            return []
        endif
    
        let l:lnums=[]
        for section_line in a:section_lines
            " trim trailing characters
            let l:lnum = substitute(section_line, '^\s\+\d\+\zs.*', '', '')
    
            " trim excess whitespace
            let l:lnum = substitute(l:lnum, '\s', '', 'g')
    
            call add(l:lnums, str2nr(l:lnum))
        endfor
    
        return l:lnums
    endfunction
    
    " define more signs, if needed
    " note: doesn't abort on error
    function! number#define_signs(sections)
        let l:biggest_diff=-1
        for section in a:sections
            let l:curr_diff=section[1]-section[0]
            let l:biggest_diff=l:curr_diff > l:biggest_diff ? l:curr_diff : l:biggest_diff
        endfor
    
        for i in range(l:biggest_diff+1)
            " fail silently when lnum is >= 100 in Vim
            " In NeoVim use :h 'signcolumn' and :h 'number' accordingly
            exec 'silent! sign define Lnum' . i . ' texthl=LineNr text=' . i
        endfor
    endfunction
    
    " place signs in buffer
    " note: doesn't abort on error
    function! number#place_signs(sections)
        " clear all of our signs for current buffer
        exec 'sign unplace * group=CustomNumber buffer=' . bufnr()
    
        " no matches
        if len(a:sections) == 0
            return
        endif
    
        " define signs, if needed
        call number#define_signs(a:sections)
    
        for section in a:sections
            let l:custom_lnum=0
            for lnum in range(section[0], section[1])
                exec 'silent! sign place ' . s:sign_id . ' line=' . lnum . ' name=Lnum' . l:custom_lnum . ' group=CustomNumber buffer=' . bufnr()
                let l:custom_lnum+=1
                let s:sign_id+=1
            endfor
        endfor
    endfunction
    
    augroup CustomNumber
        autocmd!
        autocmd BufEnter,BufNew,TextChanged,TextChangedI,TextChangedP * call number#place_signs(number#get_section_lines())
    augroup END

And here is what that looks like in Vim:

![example picture](https://i.sstatic.net/qRKYz.png)

See:

    :h 'signcolumn'
    :h :sign
    :h :sign-define
    :h :sign-place
    :h :sign-unplace