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:

    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